1 /*
2  * FIG : Facility for Interactive Generation of figures
3  * Copyright (c) 1985-1988 by Supoj Sutanthavibul
4  * Parts Copyright (c) 1989-2015 by Brian V. Smith
5  * Parts Copyright (c) 1991 by Paul King
6  * Parts Copyright (c) 2016-2020 by Thomas Loimer
7  *
8  * Any party obtaining a copy of these files is granted, free of charge, a
9  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
10  * nonexclusive right and license to deal in this software and documentation
11  * files (the "Software"), including without limitation the rights to use,
12  * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
13  * the Software, and to permit persons who receive copies from any such
14  * party to do so, with the only requirement being that the above copyright
15  * and this permission notice remain intact.
16  *
17  */
18 
19 /*
20  * This file provides some drawing primitives which make use of the
21  * underlying low-level windowing system operations.
22  *
23  * The file is divided into routines for:
24  *
25  * GRAPHICS CONTEXTS (which are used by all the following)
26  * FONTS
27  * LINES
28  * SHADING
29  */
30 
31 /* IMPORTS */
32 
33 #include "fig.h"
34 #include "figx.h"
35 #include "resources.h"
36 #include "paintop.h"
37 #include "mode.h"
38 #include "object.h"
39 #include "u_create.h"
40 #include "u_fonts.h"
41 #include "w_canvas.h"
42 #include "w_drawprim.h"
43 #include "w_indpanel.h"
44 #include "w_layers.h"
45 #include "w_msgpanel.h"
46 #include "w_setup.h"
47 #include "w_util.h"
48 
49 #include "u_create.h"
50 #include "w_cursor.h"
51 #include "w_file.h"
52 #include "w_rottext.h"
53 
54 /* EXPORTS */
55 
56 XFontStruct	*bold_font;
57 XFontStruct	*roman_font;
58 XFontStruct	*button_font;
59 XFontStruct	*canvas_font;
60 
61 /* LOCAL */
62 
63 static void	clip_line(int x1, int y1, int x2, int y2,  short *x3, short *y3, short *x4, short *y4);
64 static int	clip_poly(XPoint *inVertices, int npoints, XPoint *outVertices);
65 static void	intersect(XPoint first, XPoint second, int x1, int y1, int x2, int y2, XPoint *intersectPt);
66 static Boolean	inside (XPoint testVertex, int x1, int y1, int x2, int y2);
67 static void	setup_next(int npoints, XPoint *in, XPoint *out);
68 static Pixel	gc_color[NUMOPS], gc_background[NUMOPS];
69 static XRectangle clip[1];
70 static int	parsesize(char *name);
71 static Boolean	openwinfonts;
72 static Boolean  font_scalable[NUM_FONTS];
73 
74 #define MAXNAMES 300
75 
76 static struct {
77     char	   *fn;
78     int		    s;
79 }		flist[MAXNAMES];
80 
81 
82 void rescale_pattern (int patnum);
83 void zXFillPolygon (Display *d, Window w, GC gc, zXPoint *points, int n, int complex, int coordmode);
84 void zXDrawLines (Display *d, Window w, GC gc, zXPoint *points, int n, int coordmode);
85 void scale_pattern (int indx);
86 int SutherlandHodgmanPolygoClip (XPoint *inVertices, XPoint *outVertices, int inLength, int x1, int y1, int x2, int y2);
87 
init_font(void)88 void init_font(void)
89 {
90     struct xfont   *newfont, *nf;
91     int		    f, count, i, p, ss;
92     char	    template[300];
93     char	    backup_template[300];
94     char	  **fontlist, **fname;
95 
96     if (appres.boldFont == NULL || *appres.boldFont == '\0')
97 	appres.boldFont = BOLD_FONT;
98     if (appres.normalFont == NULL || *appres.normalFont == '\0')
99 	appres.normalFont = NORMAL_FONT;
100     if (appres.buttonFont == NULL || *appres.buttonFont == '\0')
101 	appres.buttonFont = BUTTON_FONT;
102 
103     while ((roman_font = XLoadQueryFont(tool_d, appres.normalFont)) == 0) {
104 	if (strcmp(appres.normalFont,"fixed") == 0) {
105 	    fprintf(stderr, "Can't load 'fixed' font, something is wrong");
106 	    fprintf(stderr," with your server - quitting.\n");
107 	    exit(1);
108 	}
109 	file_msg("Can't load font: %s, using 'fixed'\n", appres.normalFont);
110 	appres.normalFont = "fixed";
111     } /* now loop to load "fixed" */
112     hidden_text_length = 4 * roman_font->max_bounds.width;
113     if ((bold_font = XLoadQueryFont(tool_d, appres.boldFont)) == 0) {
114 	file_msg("Can't load font: %s, using %s\n",
115 		appres.boldFont, appres.normalFont);
116 	bold_font = XLoadQueryFont(tool_d, appres.normalFont);
117     }
118     if ((button_font = XLoadQueryFont(tool_d, appres.buttonFont)) == 0) {
119 	file_msg("Can't load font: %s, using %s\n",
120 		appres.buttonFont, appres.normalFont);
121 	button_font = XLoadQueryFont(tool_d, appres.normalFont);
122     }
123     /*
124      * Now initialize the font structure for the X fonts corresponding to the
125      * Postscript fonts for the canvas.	 OpenWindows can use any LaserWriter
126      * fonts at any size, so we don't need to load anything if we are using
127      * it.
128      */
129 
130     /* if the user hasn't disallowed scalable fonts, check that the
131        server really has them by checking for font of 0-0 size */
132     openwinfonts = False;
133     if (appres.scalablefonts) {
134 	/* first look for OpenWindow style font names (e.g. times-roman) */
135 	if ((fontlist = XListFonts(tool_d, ps_fontinfo[1].name, 1, &count))!=0) {
136             openwinfonts = True; /* yes, use them */
137             for (f=0; f<NUM_FONTS; f++) { /* copy the OpenWindow font names */
138                 x_fontinfo[f].template = ps_fontinfo[f+1].name;
139                 font_scalable[f] = True;
140             }
141             XFreeFontNames(fontlist);
142 	} else {
143             for (f = 0; f < NUM_FONTS; f++) {
144                 strcpy(template,x_fontinfo[f].template);  /* nope, check for font size 0 */
145                 strcat(template,"0-0-*-*-*-*-");
146                 /* add ISO8859 (if not Symbol font or ZapfDingbats) to font name in non-international mode*/
147                 if (
148 #ifdef I18N
149                     !appres.international &&
150 #endif
151                     strstr(template,"ymbol") == NULL &&
152                     strstr(template,"ingbats") == NULL)
153                         strcat(template,"ISO8859-*");
154                 else
155                     strcat(template,"*-*");
156 
157                 if ((fontlist = XListFonts(tool_d, template, 1, &count)))
158                     font_scalable[f] = True;
159                 else
160                     font_scalable[f] = False;
161 
162                 XFreeFontNames(fontlist);
163             }
164 	}
165     }
166 
167     /* no scalable fonts - query the server for all the font
168        names and sizes and build a list of them */
169 
170     for (f = 0; f < NUM_FONTS; f++) {
171         if (!font_scalable[f]) {
172 	    nf = NULL;
173 	    strcpy(template,x_fontinfo[f].template);
174 	    strcat(template,"*-*-*-*-*-*-");
175 	    strcpy(backup_template,x_backup_fontinfo[f].template);
176 	    strcat(backup_template,"*-*-*-*-*-*-");
177 	    /* add ISO8859 (if not Symbol font or ZapfDingbats) to font name in non-international mode*/
178 	    if (
179 #ifdef I18N
180 		!appres.international &&
181 #endif
182 		strstr(template,"ymbol") == NULL &&
183 		strstr(template,"ingbats") == NULL) {
184 		    strcat(template,"ISO8859-*");
185 		    strcat(backup_template,"ISO8859-*");
186 	    } else {
187 		strcat(template,"*-*");
188 		strcat(backup_template,"*-*");
189             }
190 	    /* don't free the Fontlist because we keep pointers into it */
191 	    p = 0;
192 
193 	    if ((fontlist = XListFonts(tool_d, template, MAXNAMES, &count))==0)
194 	        fontlist = XListFonts(tool_d, backup_template, MAXNAMES, &count);
195 
196             if (fontlist == 0) {
197 		/* no fonts by that name found, substitute the -normal font name */
198 		flist[p].fn = appres.normalFont;
199 		flist[p++].s = 12;	/* just set the size to 12 */
200 	    } else {
201 		fname = fontlist; /* go through the list finding point
202 				   * sizes */
203 		while (count--) {
204 		ss = parsesize(*fname);	/* get the point size from
205 					 * the name */
206 		flist[p].fn = *fname++;	/* save name of this size
207 					 * font */
208 		flist[p++].s = ss;	/* and save size */
209 		}
210 	    }
211 	    /* start at size 4 and go to 50 */
212 	    for (ss = 4; ss <= 50; ss++) {
213 		for (i = 0; i < p; i++)
214 			if (flist[i].s == ss)	/* found size */
215 			    break;
216 		/* if found size, allocate the font */
217 		if (i < p && flist[i].s == ss) {
218 			newfont = (struct xfont *) malloc(sizeof(struct xfont));
219 			if (nf == NULL)
220 			    x_fontinfo[f].xfontlist = newfont;
221 			else
222 			    nf->next = newfont;
223 			nf = newfont;	/* keep current ptr */
224 			nf->size = ss;	/* store the size here */
225 			if (appres.DEBUG)
226 			    fprintf(stderr,"Font: %s\n",flist[i].fn);
227 			nf->fname = flist[i].fn;	/* keep actual name */
228 			nf->fstruct = NULL;
229 		        nf->fset = NULL;
230 			nf->next = NULL;
231 		    }
232 	    } /* next size */
233         } /* !font_scalable[f] */
234     } /* next font, f */
235 }
236 
237 /* parse the point size of font 'name' */
238 /* e.g. -adobe-courier-bold-o-normal--10-100-75-75-m-60-ISO8859-1 */
239 
240 static int
parsesize(char * name)241 parsesize(char *name)
242 {
243     int		    s;
244     char	   *np;
245 
246     for (np = name; *(np + 1); np++) {
247         /* look for "--" */
248 	if (strncmp(np, "--", 2) == 0)
249 	    return atoi(np + 2);
250         /* For "-b&h-lucida-*-normal-sans-<point-size>-*" */
251         if (strncmp(np, "-normal-sans-", 13) == 0)
252 	    return atoi(np + 13);
253     }
254 
255     fprintf(stderr, "Can't parse '%s'\n", name);
256     return 0;
257 }
258 
259 /*
260  * Lookup an X font, "fnum" corresponding to a Postscript font style that is
261  * close in size to "size"
262  */
263 
264 XFontStruct *
lookfont(int fnum,int size)265 lookfont(int fnum, int size)
266 {
267 	XFontStruct    *fontst;
268 	XFontSet        fontset = NULL;
269 	char		fn[300],back_fn[300];
270 	char		template[300], *sub;
271 	Boolean		found;
272 	struct xfont   *newfont, *nf, *oldnf;
273 
274 #ifdef I18N
275 	char **mcharset;
276 	int ncharset;
277 	char *defstr;
278 #endif
279 
280 	if (fnum == DEFAULT)
281 	    fnum = 0;			/* pass back the -normal font font */
282 	if (size < 0)
283 	    size = DEF_FONTSIZE;	/* default font size */
284 	if (size < MIN_X_FONT_SIZE)
285 	    size = MIN_X_FONT_SIZE;	/* minimum allowable */
286 	else if (size > MAX_X_FONT_SIZE)
287 	    size = MAX_X_FONT_SIZE;	/* maximum allowable */
288 
289 	/* if user asks, adjust for correct font size */
290 	if (appres.correct_font_size)
291 	    size = round(size*80.0/72.0);
292 
293 	/* see if we've already loaded that font size 'size'
294 	   from the font family 'fnum' */
295 
296 	found = False;
297 
298 	/* start with the basic font name (e.g. -*-times-medium-r-normal-... */
299 
300 	nf = x_fontinfo[fnum].xfontlist;
301 	oldnf = nf;
302 	if (nf != NULL) {
303 	    if (nf->size > size && !font_scalable[fnum])
304 		found = True;
305 	    else {
306 		while (nf != NULL) {
307 		    if (nf->size == size || (!font_scalable[fnum] &&
308 			   (nf->size >= size && oldnf->size <= size))) {
309 			found = True;
310 			break;
311 		    }
312 		    oldnf = nf;
313 		    nf = nf->next;
314 		}
315 	    }
316 	}
317 	if (found) {		/* found exact size (or only larger available) */
318 	    strcpy(fn,nf->fname);  /* put the name in fn */
319 	    if (size < nf->size)
320 		put_msg("Font size %d not found, using larger %d point",size,nf->size);
321 	} else if (!font_scalable[fnum]) {	/* not found, use largest available */
322 	    nf = oldnf;
323 	    strcpy(fn,nf->fname);		/* put the name in fn */
324 	    if (size > nf->size)
325 		put_msg("Font size %d not found, using smaller %d point",size,nf->size);
326 	} else { /* scalablefonts; none yet of that size, alloc one and put it in the list */
327 	    newfont = (struct xfont *) malloc(sizeof(struct xfont));
328 	    /* add it on to the end of the list */
329 	    if (x_fontinfo[fnum].xfontlist == NULL)
330 	        x_fontinfo[fnum].xfontlist = newfont;
331 	    else
332 	        oldnf->next = newfont;
333 	    nf = newfont;		/* keep current ptr */
334 	    nf->size = size;		/* store the size here */
335 	    nf->fstruct = NULL;
336 	    nf->fset = NULL;
337 	    nf->next = NULL;
338 
339 	    if (openwinfonts) {
340 		/* OpenWindows fonts, create font name like times-roman-13 */
341 		sprintf(fn, "%s-%d", x_fontinfo[fnum].template, size);
342 	    } else {
343 		/* X11 fonts, create a full XLFD font name */
344 		strcpy(template,x_fontinfo[fnum].template);
345 		/* attach pointsize to font name */
346 		strcat(template,"%d-*-*-*-*-*-");
347 		/* add ISO8859 (if not Symbol font or ZapfDingbats) to font name in non-international mode */
348 		if (
349 #ifdef I18N
350 		    !appres.international &&
351 #endif
352 		    strstr(template,"ymbol") == NULL &&
353 		    strstr(template,"ingbats") == NULL)
354 			strcat(template,"ISO8859-*");
355 	        else
356 			strcat(template,"*-*");
357 		/* use the pixel field instead of points in the fontname so that the
358 		font scales with screen size */
359 		sprintf(fn, template, size);
360 		/* do same process with backup font name in case first doesn't exist */
361 		strcpy(template,x_backup_fontinfo[fnum].template);
362 		strcat(template,"%d-*-*-*-*-*-");
363 		/* add ISO8859 (if not Symbol font or ZapfDingbats) to font name in non-international mode */
364 		if (
365 #ifdef I18N
366 		    !appres.international &&
367 #endif
368 		    strstr(template,"ymbol") == NULL &&
369 		    strstr(template,"ingbats") == NULL)
370 			strcat(template,"ISO8859-*");
371 	        else
372 			strcat(template,"*-*");
373 		sprintf(back_fn, template, size);
374 	    }
375 	    /* allocate space for the name and put it in the structure */
376 	    nf->fname = (char *) new_string(max2(strlen(fn),strlen(back_fn)));
377 	    strcpy(nf->fname, fn);
378 	    /* save the backup name too */
379 	    nf->bname = (char *) new_string(strlen(back_fn));
380 	    strcpy(nf->bname, back_fn);
381 	} /* scalable */
382 
383 	if (nf->fstruct == NULL) {
384 	    if (appres.DEBUG)
385 		fprintf(stderr,"Loading font %s\n",fn);
386 	    /* if we are previewing a figure and the user pressed Cancel,
387 	       return now with the simple roman font */
388 	    if (check_cancel())
389 		return roman_font;
390 	    set_temp_cursor(wait_cursor);
391 	    fontst = XLoadQueryFont(tool_d, fn);
392 #ifdef I18N
393             /* create fontsets for all fonts but Symbol and Dingbats */
394 	    if (appres.international &&
395                 strstr(fn,"ymbol") == NULL &&
396 		strstr(fn,"ingbats") == NULL)
397 		  fontset = XCreateFontSet(tool_d, fn, &mcharset, &ncharset, &defstr);
398 #endif
399 	    reset_cursor();
400 	    if (fontst == NULL) {
401 		/* doesn't exist, see if substituting "condensed" for "narrow" will match */
402 		if ((sub=strstr(fn,"-narrow-")) != NULL) {
403 		    strcpy(template, fn);
404 		    strcpy(&template[sub-fn],"-condensed-");
405 		    strcat(template, (sub+8));
406 		    /* try it */
407 		    fontst = XLoadQueryFont(tool_d, template);
408 		} else {
409 		    /* doesn't exist, try backup font name */
410 		    fontst = XLoadQueryFont(tool_d, nf->bname);
411 		    if (fontst) {
412 			/* use this name instead */
413 			strcpy(nf->fname, nf->bname);
414 		    } else {
415 			/* backup name doesn't exist, see if we can substitute "condensed" for "narrow" */
416 			if ((sub=strstr(nf->bname,"-narrow-")) != NULL) {
417 			    /* see if substituting "condensed" for "narrow" will match */
418 			    strcpy(template, nf->bname);
419 			    strcpy(&template[sub-nf->bname],"-condensed-");
420 			    strcat(template, (sub+8));
421 			    /* try it */
422 			    fontst = XLoadQueryFont(tool_d, template);
423 			}
424 		    }
425 		}
426 	    }
427 	    if (fontst == NULL) {
428 		/* even that font doesn't exist, use a plain one */
429 		file_msg("Can't find %s, using %s", fn, appres.normalFont);
430 		fontst = XLoadQueryFont(tool_d, appres.normalFont);
431 		if (nf->fname)
432 		    free(nf->fname);
433 		/* allocate space for the name and put it in the structure */
434 		nf->fname = (char *) new_string(strlen(appres.normalFont));
435 		strcpy(nf->fname, appres.normalFont);  /* keep actual name */
436 	    }
437 
438 	    /* put the structure in the list */
439 	    nf->fstruct = fontst;
440 	    nf->fset = fontset;
441 	} /* if (nf->fstruct == NULL) */
442 
443 	return (nf->fstruct);
444 }
445 
446 /* print "string" in window "w" using font specified in fstruct at angle
447 	"angle" (radians) at (x,y)
448    If background is != COLOR_NONE, draw background color ala DrawImageString
449 */
450 
451 void
pw_text(Window w,int x,int y,int op,int depth,XFontStruct * fstruct,float angle,char * string,Color color,Color background)452 pw_text(Window w, int x, int y, int op, int depth, XFontStruct *fstruct,
453 	float angle, char *string, Color color, Color background)
454 {
455     int		xfg, xbg;
456 
457     if (fstruct == NULL) {
458 	fprintf(stderr,"Error, in pw_text, fstruct==NULL\n");
459 	return;
460     }
461 
462     /* if this depth is inactive, draw the text in gray */
463     /* if depth == MAX_DEPTH+1 then the caller wants the original color no matter what */
464     if (draw_parent_gray || (depth < MAX_DEPTH+1 && !active_layer(depth)))
465 	color = MED_GRAY;
466 
467     /* get the X colors */
468     xfg = x_color(color);
469     xbg = x_color(background);
470     if ((xfg != gc_color[op]) ||
471 	(background != COLOR_NONE && (xbg != gc_background[op]))) {
472 	    /* don't change the colors for ERASE */
473 	    if (op == PAINT || op == INV_PAINT) {
474 		if (op == PAINT)
475 		    set_x_fg_color(gccache[op], color);
476 		else
477 		    XSetForeground(tool_d,gccache[op], xfg ^ x_bg_color.pixel);
478 		gc_color[op] = xfg;
479 		if (background != COLOR_NONE) {
480 		    set_x_bg_color(gccache[op], background);
481 		    gc_background[op] = xbg;
482 		}
483 	    }
484     }
485 
486     /* check for preview cancel here.  The text call may take some time if
487        a large font has to be rotated. */
488     if (check_cancel())
489 	return ;
490 
491     if (background != COLOR_NONE) {
492 	zXRotDrawImageString(tool_d, fstruct, angle, w, gccache[op], x, y, string);
493     } else {
494 	zXRotDrawString(tool_d, fstruct, angle, w, gccache[op], x, y, string);
495     }
496 }
497 
498 PR_SIZE
textsize(XFontStruct * fstruct,int n,char * s)499 textsize(XFontStruct *fstruct, int n, char *s)
500 {
501     PR_SIZE	    ret;
502     int		    dir, asc, desc;
503     XCharStruct	    overall;
504 
505 #ifdef I18N
506     if (appres.international) {
507       extern void i18n_text_extents(); /* w_i18n.h */
508       i18n_text_extents(fstruct, s, n, &dir, &asc, &desc, &overall);
509       ret.length = ZOOM_FACTOR * overall.width;
510       ret.ascent = ZOOM_FACTOR * overall.ascent;
511       ret.descent = ZOOM_FACTOR * overall.descent;
512       return (ret);
513     }
514 #endif  /* I18N */
515     XTextExtents(fstruct, s, n, &dir, &asc, &desc, &overall);
516     ret.length = ZOOM_FACTOR * overall.width;
517     ret.ascent = ZOOM_FACTOR * overall.ascent;
518     ret.descent = ZOOM_FACTOR * overall.descent;
519     return (ret);
520 }
521 
522 /* LINES */
523 
524 static int	gc_thickness[NUMOPS],
525 		gc_line_style[NUMOPS],
526 		gc_join_style[NUMOPS],
527 		gc_cap_style[NUMOPS];
528 
529 GC
makegc(int op,Pixel fg,Pixel bg)530 makegc(int op, Pixel fg, Pixel bg)
531 {
532     register GC	    ngc;
533     XGCValues	    gcv;
534     unsigned long   gcmask;
535 
536     gcv.font = roman_font->fid;
537     gcv.join_style = JoinMiter;
538     gcv.cap_style = CapButt;
539     gcmask = GCJoinStyle | GCCapStyle | GCFunction | GCForeground |
540 		GCBackground | GCFont;
541     switch (op) {
542       case PAINT:
543 	gcv.foreground = fg;
544 	gcv.background = bg;
545 	gcv.function = GXcopy;
546 	break;
547       case ERASE:
548 	gcv.foreground = bg;
549 	gcv.background = bg;
550 	gcv.function = GXcopy;
551 	break;
552       case INV_PAINT:
553 	gcv.foreground = fg ^ bg;
554 	gcv.background = bg;
555 	gcv.function = GXxor;
556 	break;
557     }
558 
559     ngc = XCreateGC(tool_d, tool_w, gcmask, &gcv);
560     return (ngc);
561 }
562 
init_gc(void)563 void init_gc(void)
564 {
565     int		    i;
566     XColor	    tmp_color;
567     XGCValues	    gcv;
568 
569     gccache[PAINT] = makegc(PAINT, x_fg_color.pixel, x_bg_color.pixel);
570     gccache[ERASE] = makegc(ERASE, x_fg_color.pixel, x_bg_color.pixel);
571     gccache[INV_PAINT] = makegc(INV_PAINT, x_fg_color.pixel, x_bg_color.pixel);
572     /* parse any grid color spec */
573     XParseColor(tool_d, tool_cm, appres.grid_color, &tmp_color);
574     if (XAllocColor(tool_d, tool_cm, &tmp_color)==0) {
575 	fprintf(stderr,"Can't allocate color for grid \n");
576         grid_color = x_fg_color.pixel;
577 	grid_gc = makegc(PAINT, grid_color, x_bg_color.pixel);
578     } else {
579         grid_color = tmp_color.pixel;
580 	grid_gc = makegc(PAINT, grid_color, x_bg_color.pixel);
581     }
582 
583     for (i = 0; i < NUMOPS; i++) {
584 	gc_color[i] = -1;
585 	gc_background[i] = -1;
586 	gc_thickness[i] = -1;
587 	gc_line_style[i] = -1;
588 	gc_join_style[i] = -1;
589     }
590     /* gc for page border and axis lines */
591     border_gc = DefaultGC(tool_d, tool_sn);
592     /* set the roman font for the message window */
593     XSetFont(tool_d, border_gc, roman_font->fid);
594 
595     /* gc for picture pixmap rendering */
596     pic_gc = XCreateGC(tool_d, DefaultRootWindow(tool_d), 0, NULL);
597 
598     /* make a gc for the command buttons */
599     gcv.font = button_font->fid;
600     button_gc = XCreateGC(tool_d, DefaultRootWindow(tool_d), GCFont, &gcv);
601     /* copy the other components from the page border gc to the button_gc */
602     XCopyGC(tool_d, border_gc, ~GCFont, button_gc);
603 
604 }
605 
606 /* create the gc's for fill style (PAINT and ERASE) */
607 /* the fill_pm[] must already be created */
608 
init_fill_gc(void)609 void init_fill_gc(void)
610 {
611     XGCValues	    gcv;
612     int		    i;
613     unsigned long   mask;
614 
615     gcv.fill_style = FillOpaqueStippled;
616     gcv.arc_mode = ArcPieSlice; /* fill mode for arcs */
617     gcv.fill_rule = EvenOddRule /* WindingRule */ ;
618     for (i = 0; i < NUMFILLPATS; i++) {
619 	/* all the bits are recolored in set_fill_gc() */
620 	fill_gc[i] = makegc(PAINT, x_fg_color.pixel, x_color(BLACK));
621 	mask = GCFillStyle | GCFillRule | GCArcMode;
622 	if (fill_pm[i]) {
623 	    gcv.stipple = fill_pm[i];
624 	    mask |= GCStipple;
625 	}
626 	XChangeGC(tool_d, fill_gc[i], mask, &gcv);
627     }
628 }
629 
630 /* SHADING */
631 
632 /* grey images for fill patterns (32x32) */
633 unsigned char shade_images[NUMSHADEPATS][128] = {
634  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
635  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
636  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
637  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
638  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
639  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
640  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
641  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
642  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
643  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x88,
644  0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,
645  0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,
646  0x88,0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
647  0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
648  0x00,0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
649  0x00,0x00,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
650  0x00,0x00,0x00,0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
651  0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08},
652  {0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x00,0x00,0x00,
653  0x00,0x01,0x11,0x01,0x11,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x00,0x00,
654  0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x00,
655  0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,
656  0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x44,0x44,0x44,
657  0x44,0x00,0x00,0x00,0x00,0x01,0x11,0x01,0x11,0x00,0x00,0x00,0x00,0x44,0x44,
658  0x44,0x44,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x44,
659  0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,
660  0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00},
661  {0x00,0x00,0x00,0x00,0x11,0x51,0x11,0x51,0x00,0x00,0x00,0x00,0x44,0x44,0x44,
662  0x44,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x15,0x00,0x00,0x00,0x00,0x44,0x44,
663  0x44,0x44,0x00,0x00,0x00,0x00,0x51,0x11,0x51,0x11,0x00,0x00,0x00,0x00,0x44,
664  0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x15,0x00,0x00,0x00,0x00,
665  0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x11,0x51,0x11,0x51,0x00,0x00,0x00,
666  0x00,0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x15,0x00,0x00,
667  0x00,0x00,0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x51,0x11,0x51,0x11,0x00,
668  0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x15,
669  0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44},
670  {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,0x8a,0x88,0x8a,
671  0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,0x88,0x88,
672  0x88,0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,0x8a,
673  0x8a,0x8a,0x8a,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,
674  0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,
675  0x00,0x8a,0x88,0x8a,0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,
676  0x00,0x00,0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,
677  0x00,0x00,0x00,0x8a,0x8a,0x8a,0x8a,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
678  0x00,0x00,0x00,0x00,0x88,0x88,0x88,0x88},
679  {0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,
680  0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,
681  0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,
682  0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,
683  0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,
684  0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,
685  0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,
686  0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,
687  0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00},
688  {0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x88,0x88,0x88,
689  0x88,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x80,0x80,
690  0x80,0x80,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x88,
691  0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,
692  0x88,0x80,0x88,0x80,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,
693  0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,
694  0x55,0x55,0x80,0x80,0x80,0x80,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,
695  0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,
696  0x55,0x55,0x55,0x55,0x88,0x80,0x88,0x80},
697  {0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x80,0x80,0x80,0x80,0x55,0x55,0x55,
698  0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x88,0x08,0x88,0x08,0x55,0x55,
699  0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x80,0x80,0x80,0x80,0x55,
700  0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x08,0x08,0x08,0x08,
701  0x55,0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x80,0x80,0x80,
702  0x80,0x55,0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x88,0x08,
703  0x88,0x08,0x55,0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x80,
704  0x80,0x80,0x80,0x55,0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,
705  0x08,0x08,0x08,0x08,0x55,0x55,0x55,0x55},
706  {0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x22,0xa2,0x22,0xa2,0x55,0x55,0x55,
707  0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x2a,0x2a,0x2a,0x2a,0x55,0x55,
708  0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0xa2,0x22,0xa2,0x22,0x55,
709  0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x2a,0x2a,0x2a,0x2a,
710  0x55,0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x22,0xa2,0x22,
711  0xa2,0x55,0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x2a,0x2a,
712  0x2a,0x2a,0x55,0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0xa2,
713  0x22,0xa2,0x22,0x55,0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,
714  0x2a,0x2a,0x2a,0x2a,0x55,0x55,0x55,0x55},
715  {0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x54,0x54,0x54,
716  0x54,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x44,0x44,
717  0x44,0x44,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x44,
718  0x54,0x44,0x54,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,
719  0x44,0x44,0x44,0x44,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,
720  0xaa,0x54,0x54,0x54,0x54,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,
721  0xaa,0xaa,0x44,0x44,0x44,0x44,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,
722  0xaa,0xaa,0xaa,0x44,0x54,0x44,0x54,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,
723  0xaa,0xaa,0xaa,0xaa,0x44,0x44,0x44,0x44},
724  {0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,
725  0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,
726  0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,
727  0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,
728  0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,
729  0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,
730  0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,
731  0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,
732  0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa},
733  {0xdd,0xdd,0xdd,0xdd,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,
734  0xaa,0xd5,0xd5,0xd5,0xd5,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,
735  0xaa,0xaa,0xdd,0xdd,0xdd,0xdd,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,
736  0xaa,0xaa,0xaa,0xdd,0xd5,0xdd,0xd5,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,
737  0xaa,0xaa,0xaa,0xaa,0xdd,0xdd,0xdd,0xdd,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,
738  0x55,0xaa,0xaa,0xaa,0xaa,0xd5,0xd5,0xd5,0xd5,0xaa,0xaa,0xaa,0xaa,0x55,0x55,
739  0x55,0x55,0xaa,0xaa,0xaa,0xaa,0xdd,0xdd,0xdd,0xdd,0xaa,0xaa,0xaa,0xaa,0x55,
740  0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0xdd,0xd5,0xdd,0xd5,0xaa,0xaa,0xaa,0xaa,
741  0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa},
742  {0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xd5,0xd5,0xd5,0xd5,0xaa,0xaa,0xaa,
743  0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xdd,0x5d,0xdd,0x5d,0xaa,0xaa,
744  0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xd5,0xd5,0xd5,0xd5,0xaa,
745  0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0x5d,0xdd,0x5d,0xdd,
746  0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xd5,0xd5,0xd5,
747  0xd5,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xdd,0x5d,
748  0xdd,0x5d,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xd5,
749  0xd5,0xd5,0xd5,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,
750  0x5d,0xdd,0x5d,0xdd,0xaa,0xaa,0xaa,0xaa},
751  {0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,0x55,0xfe,0xfe,0xfe,
752  0xfe,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,0x55,0xee,0xef,
753  0xee,0xef,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,0x55,0xfe,
754  0xfe,0xfe,0xfe,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,0x55,
755  0xef,0xef,0xef,0xef,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,
756  0x55,0xfe,0xfe,0xfe,0xfe,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,
757  0x55,0x55,0xee,0xef,0xee,0xef,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,
758  0x55,0x55,0x55,0xfe,0xfe,0xfe,0xfe,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,
759  0x55,0x55,0x55,0x55,0xef,0xef,0xef,0xef},
760  {0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,
761  0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x7f,0x77,0x7f,0xaa,0xaa,
762  0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,
763  0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x7f,0x7f,0x7f,0x7f,
764  0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,
765  0x77,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x7f,
766  0x77,0x7f,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,
767  0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,
768  0x7f,0x7f,0x7f,0x7f,0xaa,0xaa,0xaa,0xaa},
769  {0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,
770  0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,
771  0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,
772  0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,
773  0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,
774  0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,
775  0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,
776  0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,
777  0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa},
778  {0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0xdd,0xdd,0xdd,0xdd,0xff,0xff,0xff,
779  0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0x5d,0xdd,0x5d,0xdd,0xff,0xff,
780  0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0xdd,0xdd,0xdd,0xdd,0xff,
781  0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0x5d,0x5d,0x5d,0x5d,
782  0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0xdd,0xdd,0xdd,
783  0xdd,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0x5d,0xdd,
784  0x5d,0xdd,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0xdd,
785  0xdd,0xdd,0xdd,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,
786  0x5d,0x5d,0x5d,0x5d,0xff,0xff,0xff,0xff},
787  {0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,0xba,0xba,0xba,0xff,0xff,0xff,
788  0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xab,0xbb,0xab,0xbb,0xff,0xff,
789  0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,0xba,0xba,0xba,0xff,
790  0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,0xab,0xbb,0xab,
791  0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,0xba,0xba,
792  0xba,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xab,0xbb,
793  0xab,0xbb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,
794  0xba,0xba,0xba,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,
795  0xbb,0xab,0xbb,0xab,0xff,0xff,0xff,0xff},
796  {0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xfb,0xfb,0xfb,
797  0xfb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbf,0xbb,
798  0xbf,0xbb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xfb,
799  0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,
800  0xbf,0xbf,0xbf,0xbf,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,
801  0xff,0xfb,0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,
802  0xff,0xff,0xbf,0xbb,0xbf,0xbb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,
803  0xff,0xff,0xff,0xfb,0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,
804  0xff,0xff,0xff,0xff,0xbf,0xbf,0xbf,0xbf},
805  {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbb,0xbb,0xbb,
806  0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xfb,
807  0xfb,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbb,
808  0xbb,0xbb,0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
809  0xfb,0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
810  0xff,0xbb,0xbb,0xbb,0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
811  0xff,0xff,0xfb,0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
812  0xff,0xff,0xff,0xbb,0xbb,0xbb,0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
813  0xff,0xff,0xff,0xff,0xfb,0xfb,0xfb,0xfb},
814  {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
815  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
816  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
817  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
818  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
819  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
820  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
821  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
822  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
823 };
824 
825 /* initial data for patterns */
826 
827 /* 30 degrees left diagonal */
828 #define left30_width 8
829 #define left30_height 4
830 static unsigned char left30_bits[] = {
831    0x03, 0x0c, 0x30, 0xc0};
832 /* 30 degrees right diagonal */
833 #define right30_width 8
834 #define right30_height 4
835 static unsigned char right30_bits[] = {
836    0xc0, 0x30, 0x0c, 0x03};
837 /* 30 degrees crosshatch */
838 #define crosshatch30_width 8
839 #define crosshatch30_height 4
840 static unsigned char crosshatch30_bits[] = {
841    0x81, 0x66, 0x18, 0x66};
842 /* 45 degrees left diagonal */
843 #define left45_width 8
844 #define left45_height 8
845 static unsigned char left45_bits[] = {
846    0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
847 /* 45 degrees right diagonal */
848 #define right45_width 8
849 #define right45_height 8
850 static unsigned char right45_bits[] = {
851    0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
852 /* 45 degrees crosshatch */
853 #define crosshatch45_width 8
854 #define crosshatch45_height 8
855 static unsigned char crosshatch45_bits[] = {
856    0x11, 0x0a, 0x04, 0x0a, 0x11, 0xa0, 0x40, 0xa0};
857 /* horizontal bricks */
858 #define bricks_width 16
859 #define bricks_height 16
860 static unsigned char bricks_bits[] = {
861    0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
862    0x00, 0x80, 0xff, 0xff, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
863    0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xff, 0xff};
864 /* vertical bricks */
865 #define vert_bricks_width 16
866 #define vert_bricks_height 16
867 static unsigned char vert_bricks_bits[] = {
868    0xff, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
869    0x80, 0x80, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
870    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
871 /* horizontal lines */
872 #define horizontal_width 8
873 #define horizontal_height 4
874 static unsigned char horizontal_bits[] = {
875    0xff, 0x00, 0x00, 0x00};
876 /* vertical lines */
877 #define vertical_width 8
878 #define vertical_height 8
879 static unsigned char vertical_bits[] = {
880    0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88};
881 /* crosshatch */
882 #define crosshatch_width 8
883 #define crosshatch_height 4
884 static unsigned char crosshatch_bits[] = {
885    0xff, 0x88, 0x88, 0x88};
886 /* left-pointing shingles */
887 #define leftshingle_width 24
888 #define leftshingle_height 24
889 static unsigned char leftshingle_bits[] = {
890    0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
891    0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff,
892    0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00,
893    0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff,
894    0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
895    0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0xff, 0xff, 0xff};
896 /* right-pointing shingles */
897 #define rightshingle_width 24
898 #define rightshingle_height 24
899 static unsigned char rightshingle_bits[] = {
900    0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20,
901    0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff,
902    0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00,
903    0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x00, 0xff, 0xff, 0xff,
904    0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00,
905    0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x00, 0x00, 0xff, 0xff, 0xff};
906 /* vertical left-pointing shingles */
907 #define vert_leftshingle_width 24
908 #define vert_leftshingle_height 24
909 static unsigned char vert_leftshingle_bits[] = {
910    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
911    0x80, 0x80, 0x81, 0x80, 0x80, 0x86, 0x80, 0x80, 0x98, 0x80, 0x80, 0xe0,
912    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
913    0x80, 0x81, 0x80, 0x80, 0x86, 0x80, 0x80, 0x98, 0x80, 0x80, 0xe0, 0x80,
914    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
915    0x81, 0x80, 0x80, 0x86, 0x80, 0x80, 0x98, 0x80, 0x80, 0xe0, 0x80, 0x80};
916 /* vertical right-pointing shingles */
917 #define vert_rightshingle_width 24
918 #define vert_rightshingle_height 24
919 static unsigned char vert_rightshingle_bits[] = {
920    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
921    0x80, 0xc0, 0x80, 0x80, 0xb0, 0x80, 0x80, 0x8c, 0x80, 0x80, 0x83, 0x80,
922    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
923    0x80, 0x80, 0xc0, 0x80, 0x80, 0xb0, 0x80, 0x80, 0x8c, 0x80, 0x80, 0x83,
924    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
925    0xc0, 0x80, 0x80, 0xb0, 0x80, 0x80, 0x8c, 0x80, 0x80, 0x83, 0x80, 0x80};
926 /* fish scales */
927 #define fishscales_width 16
928 #define fishscales_height 8
929 static unsigned char fishscales_bits[] = {
930    0x40, 0x02, 0x30, 0x0c, 0x0e, 0x70, 0x01, 0x80, 0x02, 0x40, 0x0c, 0x30,
931    0x70, 0x0e, 0x80, 0x01};
932 /* small fish scales */
933 #define small_fishscales_width 8
934 #define small_fishscales_height 8
935 static unsigned char small_fishscales_bits[] = {
936    0x01, 0x01, 0x82, 0x6c, 0x10, 0x10, 0x28, 0xc6};
937 /* circles */
938 #define circles_width 16
939 #define circles_height 16
940 static unsigned char circles_bits[] = {
941    0xe0, 0x0f, 0x18, 0x30, 0x04, 0x40, 0x02, 0x80, 0x02, 0x80, 0x01, 0x00,
942    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
943    0x02, 0x80, 0x02, 0x80, 0x04, 0x40, 0x18, 0x30};
944 /* hexagons */
945 #define hexagons_width 30
946 #define hexagons_height 18
947 static unsigned char hexagons_bits[] = {
948    0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00,
949    0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,
950    0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf8, 0x3f,
951    0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00,
952    0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
953    0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00};
954 /* octagons */
955 #define octagons_width 16
956 #define octagons_height 16
957 static unsigned char octagons_bits[] = {
958    0xe0, 0x0f, 0x10, 0x10, 0x08, 0x20, 0x04, 0x40, 0x02, 0x80, 0x01, 0x00,
959    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
960    0x02, 0x80, 0x04, 0x40, 0x08, 0x20, 0x10, 0x10};
961 /* horizontal sawtooth */
962 #define horiz_saw_width 16
963 #define horiz_saw_height 8
964 static unsigned char horiz_saw_bits[] = {
965    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x14, 0x14, 0x22, 0x22,
966    0x41, 0x41, 0x80, 0x80};
967 /* vertical sawtooth */
968 #define vert_saw_width 8
969 #define vert_saw_height 16
970 static unsigned char vert_saw_bits[] = {
971    0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10,
972    0x08, 0x04, 0x02, 0x01};
973 
974 /* patterns like bricks, etc */
975 patrn_strct pattern_images[NUMPATTERNS] = {
976     {left30_width,            left30_height,            (char*)left30_bits},
977     {right30_width,           right30_height,           (char*)right30_bits},
978     {crosshatch30_width,      crosshatch30_height,      (char*)crosshatch30_bits},
979     {left45_width,            left45_height,            (char*)left45_bits},
980     {right45_width,           right45_height,           (char*)right45_bits},
981     {crosshatch45_width,      crosshatch45_height,      (char*)crosshatch45_bits},
982     {bricks_width,            bricks_height,            (char*)bricks_bits},
983     {vert_bricks_width,       vert_bricks_height,       (char*)vert_bricks_bits},
984     {horizontal_width,        horizontal_height,        (char*)horizontal_bits},
985     {vertical_width,          vertical_height,          (char*)vertical_bits},
986     {crosshatch_width,        crosshatch_height,        (char*)crosshatch_bits},
987     {leftshingle_width,       leftshingle_height,       (char*)leftshingle_bits},
988     {rightshingle_width,      rightshingle_height,      (char*)rightshingle_bits},
989     {vert_leftshingle_width,  vert_leftshingle_height,  (char*)vert_leftshingle_bits},
990     {vert_rightshingle_width, vert_rightshingle_height, (char*)vert_rightshingle_bits},
991     {fishscales_width,        fishscales_height,        (char*)fishscales_bits},
992     {small_fishscales_width,  small_fishscales_height,  (char*)small_fishscales_bits},
993     {circles_width,           circles_height,           (char*)circles_bits},
994     {hexagons_width,          hexagons_height,          (char*)hexagons_bits},
995     {octagons_width,          octagons_height,          (char*)octagons_bits},
996     {horiz_saw_width,         horiz_saw_height,         (char*)horiz_saw_bits},
997     {vert_saw_width,          vert_saw_height,          (char*)vert_saw_bits}
998 };
999 
1000 /* generate the fill pixmaps */
1001 
init_fill_pm(void)1002 void init_fill_pm(void)
1003 {
1004     int		    i,j;
1005 
1006     for (i = 0; i <= NUMFILLPATS; i++) {
1007 	fillstyle_choices[i].value = i;
1008 	fillstyle_choices[i].icon = &none_ic;
1009     }
1010 
1011     /**********************************************************************************/
1012     /* NOTE:  All fillstyle_choices pixmaps will be recolored in recolor_fillstyles() */
1013     /**********************************************************************************/
1014 
1015     /* use same colors for "NONE" indicator for black and color */
1016     fillstyle_choices[0].pixmap = XCreatePixmapFromBitmapData(tool_d,
1017 			tool_w, none_ic.bits, none_ic.width,
1018 			none_ic.height, x_fg_color.pixel, x_bg_color.pixel,
1019 			tool_dpth);
1020 
1021     /* Shade patterns go from full black to full saturation of the color */
1022     for (i = 0; i < NUMSHADEPATS; i++) {
1023 	fill_pm[i] = XCreateBitmapFromData(tool_d, tool_w,
1024 				   (char*)shade_images[i], SHADE_IM_SIZE, SHADE_IM_SIZE);
1025 	/* create fill style pixmaps for indicator button */
1026 	/* The actual colors of fg/bg will be reset in recolor_fillstyles */
1027 	fillstyle_choices[i + 1].pixmap = XCreatePixmapFromBitmapData(tool_d,
1028 		 tool_w, (char*)shade_images[i], SHADE_IM_SIZE, SHADE_IM_SIZE,
1029 		 x_fg_color.pixel,x_bg_color.pixel,tool_dpth);
1030     }
1031     /* Tint patterns go from full saturation of the color to full white */
1032     /* Note that there are no fillstyle_choices for tints for black */
1033     for (i = NUMSHADEPATS; i < NUMSHADEPATS+NUMTINTPATS; i++) {
1034 	j = NUMSHADEPATS+NUMTINTPATS-i-1;	/* reverse the patterns */
1035 	fill_pm[i] = XCreateBitmapFromData(tool_d, tool_w,
1036 				   (char*)shade_images[j], SHADE_IM_SIZE, SHADE_IM_SIZE);
1037 	/* create fill style pixmaps for indicator button */
1038 	/* The actual colors of fg/bg will be reset in recolor_fillstyles */
1039 	fillstyle_choices[i + 1].pixmap = XCreatePixmapFromBitmapData(tool_d,
1040 		 tool_w, (char*)shade_images[j], SHADE_IM_SIZE, SHADE_IM_SIZE,
1041 		 x_fg_color.pixel,x_bg_color.pixel,tool_dpth);
1042     }
1043     /* Now do the remaining patterns (bricks, shingles, etc) */
1044     for (i = NUMSHADEPATS+NUMTINTPATS; i < NUMFILLPATS; i++) {
1045 	/* create pattern at this zoom */
1046 	rescale_pattern(i);
1047 	j = i-(NUMSHADEPATS+NUMTINTPATS);
1048 	/* save these patterns at zoom = 1 for the fill button panel */
1049 	fill_but_pm[j] = fill_pm[i];
1050 	fill_but_pm_zoom[j] = fill_pm_zoom[i];
1051 	/* to force new pixmaps for canvas */
1052 	fill_pm[i] = (Pixmap) 0;
1053 	/* and create another one */
1054 	rescale_pattern(i);
1055 	/* create fill style pixmaps for indicator button */
1056 	/* The actual colors of fg/bg will be reset in recolor_fillstyles */
1057 	fillstyle_choices[i + 1].pixmap = XCreatePixmapFromBitmapData(tool_d,
1058 		 tool_w, pattern_images[j].odata,
1059 		 pattern_images[j].owidth, pattern_images[j].oheight,
1060 		 x_fg_color.pixel,x_bg_color.pixel,tool_dpth);
1061     }
1062 }
1063 
1064 void
pw_vector(Window w,int x1,int y1,int x2,int y2,int op,int line_width,int line_style,float style_val,Color color)1065 pw_vector(Window w, int x1, int y1, int x2, int y2, int op,
1066 	  int line_width, int line_style, float style_val, Color color)
1067 {
1068     if (line_width == 0)
1069 	return;
1070     set_line_stuff(line_width, line_style, style_val, JOIN_MITER, CAP_BUTT, op, color);
1071     if (line_style == PANEL_LINE)
1072 	XDrawLine(tool_d, w, gccache[op], x1, y1, x2, y2);
1073     else
1074 	zXDrawLine(tool_d, w, gccache[op], x1, y1, x2, y2);
1075 }
1076 
1077 void
pw_curve(Window w,int xstart,int ystart,int xend,int yend,int op,int depth,int linewidth,int style,float style_val,int fill_style,Color pen_color,Color fill_color,int cap_style)1078 pw_curve(Window w, int xstart, int ystart, int xend, int yend,
1079 	 int op, int depth, int linewidth, int style, float style_val, int fill_style,
1080 	 Color pen_color, Color fill_color, int cap_style)
1081 {
1082     int		    xmin, ymin;
1083     unsigned int    wd, ht;
1084 
1085     /* if this depth is inactive, draw the curve and any fill in gray */
1086     /* if depth == MAX_DEPTH+1 then the caller wants the original color no matter what */
1087     if (draw_parent_gray || (depth < MAX_DEPTH+1 && !active_layer(depth))) {
1088 	pen_color = MED_GRAY;
1089 	fill_color = LT_GRAY;
1090     }
1091 
1092     xmin = min2(xstart, xend);
1093     ymin = min2(ystart, yend);
1094     wd = (unsigned int) abs(xstart - xend);
1095     ht = (unsigned int) abs(ystart - yend);
1096 
1097     /* if it's a fill pat we know about */
1098     if (fill_style >= 0 && fill_style < NUMFILLPATS) {
1099 	set_fill_gc(fill_style, op, pen_color, fill_color, xstart, ystart);
1100 	zXFillArc(tool_d, w, fillgc, xmin, ymin, wd, ht, 0, 360 * 64);
1101     }
1102     if (linewidth == 0)
1103 	return;
1104     if (op == ERASE) {
1105 	/* kludge - to speed things up we erase with thick solid lines */
1106 	set_line_stuff(linewidth + 3, SOLID_LINE, 0.0, JOIN_MITER,
1107 			cap_style, op, pen_color);
1108 	zXDrawArc(tool_d, w, gccache[op], xmin, ymin, wd, ht, 0, 360 * 64);
1109     } else {
1110 	set_line_stuff(linewidth, style, style_val, JOIN_MITER,
1111 			cap_style, op, pen_color);
1112 	zXDrawArc(tool_d, w, gccache[op], xmin, ymin, wd, ht, 0, 360 * 64);
1113     }
1114 }
1115 
1116 /* a point object - actually draw a line from (x-line_width/2,y) to (x+linewidth/2,y)
1117 	so that we get some thickness */
1118 
1119 void
pw_point(Window w,int x,int y,int op,int depth,int line_width,Color color,int cap_style)1120 pw_point(Window w, int x, int y, int op, int depth, int line_width,
1121 	 Color color, int cap_style)
1122 {
1123     int		    hf_wid;
1124 
1125     /* if this depth is inactive, draw the point in gray */
1126     if (draw_parent_gray || !active_layer(depth))
1127 	color = MED_GRAY;
1128 
1129     /* pw_point doesn't use line_style or fill_style but needs color */
1130     set_line_stuff(line_width, SOLID_LINE, 0.0, JOIN_MITER, cap_style,
1131 		op, color);
1132     if (cap_style > 0)
1133 	hf_wid = 0;
1134     else
1135 	hf_wid = (int)(ZOOM_FACTOR*line_width/2);
1136     /* add one to the right if the line_width is odd */
1137     zXDrawLine(tool_d, w, gccache[op], x-hf_wid, y, x+hf_wid+(line_width%2), y);
1138 }
1139 
1140 void
pw_arcbox(Window w,int xmin,int ymin,int xmax,int ymax,int radius,int op,int depth,int line_width,int line_style,float style_val,int fill_style,Color pen_color,Color fill_color)1141 pw_arcbox(Window w, int xmin, int ymin, int xmax, int ymax, int radius,
1142 	  int op, int depth, int line_width, int line_style,
1143 	  float style_val, int fill_style, Color pen_color, Color fill_color)
1144 {
1145     GC		    gc;
1146     int		    diam = 2 * radius;
1147 
1148     /* if this depth is inactive, draw the arcbox in gray */
1149     if (draw_parent_gray || (depth < MAX_DEPTH+1 && !active_layer(depth))) {
1150 	pen_color = MED_GRAY;
1151 	fill_color = LT_GRAY;
1152     }
1153 
1154     /* if it's a fill pat we know about */
1155     if (fill_style >= 0 && fill_style < NUMFILLPATS) {
1156 	set_fill_gc(fill_style, op, pen_color, fill_color, xmin, ymin);
1157 	/* upper left */
1158 	zXFillArc(tool_d, w, fillgc, xmin, ymin, diam, diam, 90 * 64, 90 * 64);
1159 	/* lower left */
1160 	zXFillArc(tool_d, w, fillgc, xmin, ymax - diam, diam, diam, 180 * 64, 90 * 64);
1161 	/* lower right */
1162 	zXFillArc(tool_d, w, fillgc, xmax - diam, ymax - diam, diam, diam, 270 * 64, 90 * 64);
1163 	/* upper right */
1164 	zXFillArc(tool_d, w, fillgc, xmax - diam, ymin, diam, diam, 0 * 64, 90 * 64);
1165 	/* fill strip on left side between upper and lower arcs */
1166 	if (ymax - ymin - diam > 0)
1167 	    zXFillRectangle(tool_d, w, fillgc, xmin, ymin + radius, radius,
1168 			    ymax - ymin - diam + 1);
1169 	/* fill middle section */
1170 	if (xmax - xmin - diam > 0)
1171 	    zXFillRectangle(tool_d, w, fillgc, xmin + radius, ymin,
1172 			    xmax - xmin - diam + 1, ymax - ymin + 1);
1173 	/* fill strip on right side between upper and lower arcs */
1174 	if (ymax - ymin - diam > 0)
1175 	    zXFillRectangle(tool_d, w, fillgc, xmax - radius, ymin + radius,
1176 			    radius, ymax - ymin - diam + 1);
1177     }
1178     if (line_width == 0)
1179 	return;
1180 
1181     set_line_stuff(line_width, line_style, style_val, JOIN_MITER, CAP_BUTT,
1182 		op, pen_color);
1183     gc = gccache[op];
1184     /* now draw the edges and arc corners */
1185     zXDrawArc(tool_d, w, gc, xmin, ymin, diam, diam, 90 * 64, 90 * 64);
1186     zXDrawLine(tool_d, w, gc, xmin, ymin + radius, xmin, ymax - radius + 1);
1187     zXDrawArc(tool_d, w, gc, xmin, ymax - diam, diam, diam, 180 * 64, 90 * 64);
1188     zXDrawLine(tool_d, w, gc, xmin + radius, ymax, xmax - radius + 1, ymax);
1189     zXDrawArc(tool_d, w, gc, xmax - diam, ymax - diam, diam, diam, 270 * 64, 90 * 64);
1190     zXDrawLine(tool_d, w, gc, xmax, ymax - radius, xmax, ymin + radius - 1);
1191     zXDrawArc(tool_d, w, gc, xmax - diam, ymin, diam, diam, 0 * 64, 90 * 64);
1192     zXDrawLine(tool_d, w, gc, xmax - radius, ymin, xmin + radius - 1, ymin);
1193 }
1194 
1195 void
pw_lines(Window w,zXPoint * points,int npoints,int op,int depth,int line_width,int line_style,float style_val,int join_style,int cap_style,int fill_style,Color pen_color,Color fill_color)1196 pw_lines(Window w, zXPoint *points, int npoints, int op, int depth,
1197 	 int line_width, int line_style, float style_val,
1198 	 int join_style, int cap_style, int fill_style,
1199 	 Color pen_color, Color fill_color)
1200 {
1201     register int i;
1202     register XPoint *p;
1203 
1204     /* if this depth is inactive, draw the line in gray */
1205     if (draw_parent_gray || (depth < MAX_DEPTH+1 && !active_layer(depth))) {
1206 	pen_color = MED_GRAY;
1207 	fill_color = LT_GRAY;
1208     }
1209 
1210     /* if the line has only one point or it has two points and those points are
1211        coincident AND we are drawing a DOTTED line, this kills Xsun and hangs
1212        other servers.
1213        We will just call pw_point since it is only a point anyway */
1214 
1215     if ((npoints == 1) ||
1216 	(npoints == 2 && points[0].x == points[1].x && points[0].y == points[1].y)) {
1217 	    pw_point(w, points[0].x, points[0].y, op, depth, line_width, pen_color, cap_style);
1218 	    return;
1219     }
1220 
1221     if (line_style == PANEL_LINE) {
1222 	/* must use XPoint, not our zXPoint */
1223 	p = (XPoint *) malloc(npoints * sizeof(XPoint));
1224 	for (i=0; i<npoints; i++) {
1225 	    p[i].x = (short) points[i].x;
1226 	    p[i].y = (short) points[i].y;
1227 	}
1228     }
1229 
1230     /* if it's a fill pat we know about, find upper-left corner for pattern origin */
1231     if (fill_style >= 0 && fill_style < NUMFILLPATS) {
1232 	int xmin=100000, ymin=100000, i;
1233 	if (fill_style >= NUMTINTPATS+NUMSHADEPATS) {
1234 	    for (i=0; i<npoints; i++) {
1235 		xmin = min2(xmin,points[i].x);
1236 		ymin = min2(ymin,points[i].y);
1237 	    }
1238 	}
1239 	else {
1240 		xmin = ymin = 0;
1241 	}
1242 	set_fill_gc(fill_style, op, pen_color, fill_color, xmin, ymin);
1243 	if (line_style == PANEL_LINE) {
1244 	    XFillPolygon(tool_d, w, fillgc, p, npoints,
1245 			 Complex, CoordModeOrigin);
1246 	} else {
1247 	    zXFillPolygon(tool_d, w, fillgc, points, npoints,
1248 			  Complex, CoordModeOrigin);
1249 	}
1250     }
1251     if (line_width == 0)
1252 	return;
1253     set_line_stuff(line_width, line_style, style_val, join_style, cap_style,
1254 			op, pen_color);
1255     if (line_style == PANEL_LINE) {
1256 	XDrawLines(tool_d, w, gccache[op], p, npoints, CoordModeOrigin);
1257 	free((char *) p);
1258     } else {
1259 	zXDrawLines(tool_d, w, gccache[op], points, npoints, CoordModeOrigin);
1260     }
1261 }
1262 
set_clip_window(int xmin,int ymin,int xmax,int ymax)1263 void set_clip_window(int xmin, int ymin, int xmax, int ymax)
1264 {
1265     clip_xmin = clip[0].x = xmin;
1266     clip_ymin = clip[0].y = ymin;
1267     clip_xmax = xmax;
1268     clip_ymax = ymax;
1269     clip_width = clip[0].width = xmax - xmin + 1;
1270     clip_height = clip[0].height = ymax - ymin + 1;
1271     XSetClipRectangles(tool_d, border_gc, 0, 0, clip, 1, YXBanded);
1272     XSetClipRectangles(tool_d, gccache[PAINT], 0, 0, clip, 1, YXBanded);
1273     XSetClipRectangles(tool_d, gccache[INV_PAINT], 0, 0, clip, 1, YXBanded);
1274     XSetClipRectangles(tool_d, gccache[ERASE], 0, 0, clip, 1, YXBanded);
1275 }
1276 
set_zoomed_clip_window(int xmin,int ymin,int xmax,int ymax)1277 void set_zoomed_clip_window(int xmin, int ymin, int xmax, int ymax)
1278 {
1279     set_clip_window(ZOOMX(xmin), ZOOMY(ymin), ZOOMX(xmax), ZOOMY(ymax));
1280 }
1281 
reset_clip_window(void)1282 void reset_clip_window(void)
1283 {
1284     set_clip_window(0, 0, CANVAS_WD, CANVAS_HT);
1285 }
1286 
set_fill_gc(int fill_style,int op,int pencolor,int fillcolor,int xorg,int yorg)1287 void set_fill_gc(int fill_style, int op, int pencolor, int fillcolor, int xorg, int yorg)
1288 {
1289     Color	    fg, bg;
1290 
1291     /* see if we need to create this fill style if it is a pattern.
1292        This might have happened if there was a change of zoom. */
1293 
1294     if ((fill_style >= NUMSHADEPATS+NUMTINTPATS) &&
1295 	((fill_pm[fill_style] == 0) || (fill_pm_zoom[fill_style] != display_zoomscale)))
1296 	    rescale_pattern(fill_style);
1297     fillgc = fill_gc[fill_style];
1298     if (op != ERASE) {
1299 	/* if a pattern, color the lines in the pen color and the field in fill color */
1300 	if (fill_style >= NUMSHADEPATS+NUMTINTPATS) {
1301 	    fg = x_color(pencolor);
1302 	    bg = x_color(fillcolor);
1303 	} else {
1304 	    if (fillcolor == BLACK) {
1305 		fg = x_color(BLACK);
1306 		bg = x_color(WHITE);
1307 	    } else if (fillcolor == DEFAULT) {
1308 		fg = x_fg_color.pixel;
1309 		bg = x_bg_color.pixel;
1310 	    } else {
1311 		fg = x_color(fillcolor);
1312 		bg = (fill_style < NUMSHADEPATS? x_color(BLACK): x_color(WHITE));
1313 	    }
1314 	}
1315     } else {
1316 	fg = x_bg_color.pixel;   /* un-fill */
1317 	bg = x_bg_color.pixel;
1318     }
1319     XSetForeground(tool_d,fillgc,fg);
1320     XSetBackground(tool_d,fillgc,bg);
1321     /* set stipple from the fill_pm array */
1322     XSetStipple(tool_d, fillgc, fill_pm[fill_style]);
1323     /* set origin of pattern relative to object itself */
1324     XSetTSOrigin(tool_d, fillgc, ZOOMX(xorg), ZOOMY(yorg));
1325     XSetClipRectangles(tool_d, fillgc, 0, 0, clip, 1, YXBanded);
1326 }
1327 
1328 
1329 static unsigned char dash_list[16][8] = {
1330 		    {255, 255, 255, 255, 255, 255, 255, 255},
1331 		    {255, 255, 255, 255, 255, 255, 255, 255},
1332 		    {255, 255, 255, 255, 255, 255, 255, 255},
1333 		    {255, 255, 255, 255, 255, 255, 255, 255},
1334 		    {255, 255, 255, 255, 255, 255, 255, 255},
1335 		    {255, 255, 255, 255, 255, 255, 255, 255},
1336 		    {255, 255, 255, 255, 255, 255, 255, 255},
1337 		    {255, 255, 255, 255, 255, 255, 255, 255},
1338 		    {255, 255, 255, 255, 255, 255, 255, 255},
1339 		    {255, 255, 255, 255, 255, 255, 255, 255},
1340 		    {255, 255, 255, 255, 255, 255, 255, 255},
1341 		    {255, 255, 255, 255, 255, 255, 255, 255},
1342 		    {255, 255, 255, 255, 255, 255, 255, 255},
1343 		    {255, 255, 255, 255, 255, 255, 255, 255},
1344 		    {255, 255, 255, 255, 255, 255, 255, 255},
1345 		    {255, 255, 255, 255, 255, 255, 255, 255}};
1346 
1347 static int join_styles[3] = { JoinMiter, JoinRound, JoinBevel };
1348 static int cap_styles[3] = { CapButt, CapRound, CapProjecting };
1349 
1350 static int ndash_dot = 4;
1351 static float dash_dot[4] = { 1., 0.5, 0., 0.5 };
1352 static int ndash_2dots = 6;
1353 static float dash_2dots[6] = { 1., 0.45, 0., 0.333, 0., 0.45 };
1354 static int ndash_3dots = 8;
1355 static float dash_3dots[8] = { 1., 0.4, 0., 0.3, 0., 0.3, 0., 0.4 };
1356 
1357 
set_line_stuff(int width,int style,float style_val,int join_style,int cap_style,int op,int color)1358 void set_line_stuff(int width, int style, float style_val, int join_style, int cap_style, int op, int color)
1359 {
1360     XGCValues	    gcv;
1361     unsigned long   mask;
1362 
1363     switch (style) {
1364       case RUBBER_LINE:
1365 	width = 0;
1366 	break;
1367       case PANEL_LINE:
1368 	break;
1369       default:
1370 	width = round(display_zoomscale * (width > 1 ? width - 1 : 0.5));
1371 	break;
1372     }
1373 
1374     /* user zero-width lines for speed with SOLID lines */
1375     /* can't do this for dashed lines because server isn't */
1376     /* required to draw dashes for zero-width lines */
1377     if (width == 1 && style == SOLID_LINE)
1378 	width = 0;
1379     /* conversely, if the width is calculated to 0 and this is a dashed line, make width 1 */
1380     if (width == 0 && style != SOLID_LINE)
1381 	width = 1;
1382 
1383     /* see if all gc stuff is already correct */
1384 
1385     if (width == gc_thickness[op] && style == gc_line_style[op] &&
1386 	join_style == gc_join_style[op] &&
1387 	cap_style == gc_cap_style[op] &&
1388 	(x_color(color) == gc_color[op]) &&
1389 	((style != DASH_LINE && style != DOTTED_LINE &&
1390           style != DASH_DOT_LINE && style != DASH_2_DOTS_LINE &&
1391           style != DASH_3_DOTS_LINE) ||
1392 	 dash_list[op][1] == (unsigned char) round(style_val * display_zoomscale)))
1393 	    return;			/* no need to change anything */
1394 
1395     gcv.line_width = width;
1396     mask = GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle;
1397     if (op == PAINT) {
1398 	gcv.foreground = x_color(color);
1399 	mask |= GCForeground;
1400     } else if (op == INV_PAINT) {
1401 	gcv.foreground = x_color(color) ^ x_bg_color.pixel;
1402 	mask |= GCForeground;
1403     }
1404     gcv.join_style = join_styles[join_style];
1405     gcv.cap_style = cap_styles[cap_style];
1406     gcv.line_style = (style == DASH_LINE || style == DOTTED_LINE ||
1407              style == DASH_DOT_LINE || style == DASH_2_DOTS_LINE ||
1408              style == DASH_3_DOTS_LINE) ?
1409 	LineOnOffDash : LineSolid;
1410 
1411     XChangeGC(tool_d, gccache[op], mask, &gcv);
1412     if (style_val > 0.0) {	/* style_val of 0.0 causes problems */
1413 	if (style == DASH_LINE || style == DOTTED_LINE) {
1414 	    /* length of ON/OFF pixels */
1415 	    if (style_val * display_zoomscale > 255.0)
1416 		dash_list[op][0] = dash_list[op][1] = (char) 255;	/* too large for X! */
1417 	    else
1418 	        dash_list[op][0] = dash_list[op][1] =
1419 				(char) round(style_val * display_zoomscale);
1420 	    /* length of ON pixels for dotted */
1421 	    if (style == DOTTED_LINE)
1422 		dash_list[op][0] = (char)display_zoomscale;
1423 
1424 	    if (dash_list[op][0]==0)		/* take care for rounding to zero ! */
1425 		dash_list[op][0]=1;
1426 	    if (dash_list[op][1]==0)		/* take care for rounding to zero ! */
1427 		dash_list[op][1]=1;
1428 	    XSetDashes(tool_d, gccache[op], 0, (char *) dash_list[op], 2);
1429 	} else if (style == DASH_DOT_LINE || style == DASH_2_DOTS_LINE ||
1430 		  style == DASH_3_DOTS_LINE) {
1431             int il, nd;
1432             float *fl;
1433             if (style == DASH_2_DOTS_LINE) {
1434 		fl=dash_2dots;
1435 		nd=ndash_2dots;
1436 	    } else if (style == DASH_3_DOTS_LINE) {
1437 		fl=dash_3dots;
1438 		nd=ndash_3dots;
1439 	    } else {
1440 		fl=dash_dot;
1441 		nd=ndash_dot;
1442 	    }
1443 	    for (il =0; il<nd; il ++) {
1444                 if (fl[il] != 0.) {
1445 		    if (fl[il] * style_val * display_zoomscale > 255.0)
1446 			dash_list[op][il] = (char) 255;	/* too large for X! */
1447 		    else
1448 			dash_list[op][il] = (char) round(fl[il] * style_val *
1449 					display_zoomscale);
1450 		} else {
1451 		    dash_list[op][il] = (char)display_zoomscale;
1452 		}
1453 		if (dash_list[op][il]==0)	/* take care for rounding to zero ! */
1454 			dash_list[op][il]=1;
1455 	    }
1456 	    XSetDashes(tool_d, gccache[op], 0, (char *) dash_list[op], nd);
1457 	}
1458     }
1459     gc_thickness[op] = width;
1460     gc_line_style[op] = style;
1461     gc_join_style[op] = join_style;
1462     gc_cap_style[op] = cap_style;
1463     gc_color[op] = x_color(color);
1464 }
1465 
1466 int
x_color(int col)1467 x_color(int col)
1468 {
1469 	int	pix;
1470 	if (!all_colors_available) {
1471 		pix = colors[BLACK];
1472 	} else if (col == LT_GRAY) {
1473 		pix = lt_gray_color;
1474 	} else if (col == DARK_GRAY) {
1475 		pix = dark_gray_color;
1476 	} else if (col == MED_GRAY) {
1477 		pix = med_gray_color;
1478 	} else if (col == TRANSP_BACKGROUND) {
1479 		pix = med_gray_color;
1480 	} else if (col == COLOR_NONE) {
1481 		pix = colors[WHITE];
1482 	} else if (col==WHITE) {
1483 		pix = colors[WHITE];
1484 	} else if (col==BLACK) {
1485 		pix = colors[BLACK];
1486 	} else if (col==DEFAULT) {
1487 		pix = x_fg_color.pixel;
1488 	} else if (col==CANVAS_BG) {
1489 		pix = x_bg_color.pixel;
1490 	} else {
1491 	   if (col < 0)
1492 		col = BLACK;
1493 	   if (col >= NUM_STD_COLS+num_usr_cols)
1494 	       pix = x_fg_color.pixel;
1495 	   else
1496 	       pix = colors[col];
1497 	}
1498 	return pix;
1499 }
1500 
1501 /* resize the fill patterns for the current display_zoomscale */
1502 /* also generate new Pixmaps in fill_pm[] */
1503 
rescale_pattern(int patnum)1504 void rescale_pattern(int patnum)
1505 {
1506 	int		j;
1507 	XGCValues	gcv;
1508 
1509 	/* this make a few seconds (depending on the machine) */
1510 	set_temp_cursor(wait_cursor);
1511 	j = patnum-(NUMSHADEPATS+NUMTINTPATS);
1512 	/* first rescale the data */
1513 	scale_pattern(j);
1514 	/* free any old pixmaps before creating new ones */
1515 	if (fill_pm[patnum]) {
1516 		XFreePixmap(tool_d,fill_pm[patnum]);
1517 	}
1518 	fill_pm[patnum] = XCreateBitmapFromData(tool_d, tool_w,
1519 				   pattern_images[j].cdata,
1520 				   pattern_images[j].cwidth,
1521 				   pattern_images[j].cheight);
1522 	/* set the zoom value so we know what zoom it was generated for */
1523 	fill_pm_zoom[patnum] = display_zoomscale;
1524 	/* now update the gc to use the new pixmaps */
1525 	if (fill_gc[patnum]) {
1526 	    gcv.stipple = fill_pm[patnum];
1527 	    XChangeGC(tool_d, fill_gc[patnum], GCStipple, &gcv);
1528 	}
1529 	reset_cursor();
1530 }
1531 
scale_pattern(int indx)1532 void scale_pattern(int indx)
1533 {
1534     int	    i;
1535     int	    j;
1536     char   *odata;
1537     char   *ndata;
1538     int	    nbytes;
1539     int	    obytes;
1540     int	    ibit;
1541     int	    jbit;
1542     int	    wbit;
1543     int	    width, height;
1544     int	    nwidth, nheight;
1545 
1546     width = pattern_images[indx].owidth;
1547     height = pattern_images[indx].oheight;
1548 
1549     nwidth = display_zoomscale * width;
1550     nheight = display_zoomscale * height;
1551 
1552     /* if already correct size just return */
1553     if (nwidth ==pattern_images[indx].cwidth &&
1554 	nheight==pattern_images[indx].cheight)
1555 		return;
1556 
1557     /* prevent 0-size bitmaps */
1558     if (nwidth == 0)
1559 	nwidth = 1;
1560     if (nheight == 0)
1561 	nheight = 1;
1562 
1563     obytes = (width + 7) / 8;
1564     nbytes = (nwidth + 7) / 8;
1565 
1566     odata = pattern_images[indx].odata;
1567     ndata = pattern_images[indx].cdata;
1568     /* if was already scaled before free that data */
1569     if (ndata)
1570 	    free(ndata);
1571     /* allocate new space for zoomed bytes */
1572     pattern_images[indx].cdata = ndata = (char *) malloc(nbytes * nheight);
1573     memset(ndata, 0, (size_t)(nbytes * nheight));
1574 
1575     /* create a new bitmap at the specified size (requires interpolation) */
1576     if (nwidth >= width) {		/* new is larger, loop over its matrix */
1577 	for (j = 0; j < nheight; j++) {
1578 	    jbit = height * j / nheight * obytes;
1579 	    for (i = 0; i < nwidth; i++) {
1580 		ibit = width * i / nwidth;	/* xy bit position from original bitmap */
1581 		wbit = *(odata + jbit + ibit / 8);
1582 		if (wbit & (1 << (ibit & 7)))
1583 		    *(ndata + j * nbytes + i / 8) |= (1 << (i & 7));
1584 	    }
1585 	}
1586     } else {	/* new is smaller, loop over orig matrix so we don't lose bits */
1587 	for (j = 0; j < height; j++) {
1588 	    jbit = nheight * j / height * nbytes;
1589 	    for (i = 0; i < width; i++) {
1590 		ibit = nwidth * i / width;	/* xy bit position from new bitmap */
1591 		wbit = *(odata + j * obytes + i / 8);
1592 		if (wbit & (1 << (i & 7)))
1593 		    *(ndata + jbit + ibit / 8) |= (1 << (ibit & 7));
1594 	    }
1595 	}
1596     }
1597     pattern_images[indx].cwidth = nwidth;
1598     pattern_images[indx].cheight = nheight;
1599 }
1600 
1601 /* storage for conversion of data points to screen coords (zXDrawLines and zXFillPolygon) */
1602 
1603 static XPoint	*_pp_ = (XPoint *) NULL;	/* data pointer itself */
1604 static int	 _npp_ = 0;			/* number of points currently allocated */
1605 static Boolean	 _noalloc_ = False;		/* signals previous failed alloc */
1606 static Boolean	 chkalloc(int n);
1607 static void	 convert_sh(zXPoint *p, int n);
1608 
zXDrawLines(Display * d,Window w,GC gc,zXPoint * points,int n,int coordmode)1609 void zXDrawLines(Display *d, Window w, GC gc, zXPoint *points, int n, int coordmode)
1610 {
1611 #ifdef CLIP_LINE
1612     XPoint	*outp;
1613 #endif /* CLIP_LINE */
1614 
1615     /* make sure we have allocated data */
1616     if (!chkalloc(n)) {
1617 	return;
1618     }
1619     /* now convert each point to short into _pp_ */
1620     convert_sh(points, n);
1621 #ifdef CLIP_LINE
1622     outp = (XPoint *) malloc(2*n*sizeof(XPoint));
1623     n = clip_poly(_pp_, n, outp);
1624     XDrawLines(d, w, gc, outp, n, coordmode);
1625 #else
1626     XDrawLines(d, w, gc, _pp_, n, coordmode);
1627 #endif /* CLIP_LINE */
1628 }
1629 
zXFillPolygon(Display * d,Window w,GC gc,zXPoint * points,int n,int complex,int coordmode)1630 void zXFillPolygon(Display *d, Window w, GC gc, zXPoint *points, int n, int complex, int coordmode)
1631 {
1632     XPoint	*outp;
1633 
1634     /* make sure we have allocated data for _pp_ */
1635     if (!chkalloc(n)) {
1636 	return;
1637     }
1638     /* now convert each point to short into _pp_ */
1639     convert_sh(points, n);
1640     outp = (XPoint *) malloc(2*n*sizeof(XPoint));
1641     n = clip_poly(_pp_, n, outp);
1642     XFillPolygon(d, w, gc, outp, n, complex, coordmode);
1643     free(outp);
1644 }
1645 
1646 /* convert each point to short */
1647 
1648 static void
convert_sh(zXPoint * p,int n)1649 convert_sh(zXPoint *p, int n)
1650 {
1651     int		 i;
1652 
1653     for (i=0; i<n; i++) {
1654 	_pp_[i].x = ZOOMX(p[i].x);
1655 	_pp_[i].y = ZOOMY(p[i].y);
1656     }
1657 }
1658 
1659 static Boolean
chkalloc(int n)1660 chkalloc(int n)
1661 {
1662     int		 i;
1663     XPoint	*tpp;
1664 
1665     /* see if we need to allocate some (more) memory */
1666     if (n > _npp_) {
1667 	/* if previous allocation failed, return now */
1668 	if (_noalloc_)
1669 	    return False;
1670 	/* get either what we need +50 points or 500, whichever is larger */
1671 	i = max2(n+50, 500);
1672 	if (_npp_ == 0) {
1673 	    if ((tpp = (XPoint *) malloc(i * sizeof(XPoint))) == 0) {
1674 		fprintf(stderr,"\007Can't alloc memory for %d point array, exiting\n",i);
1675 		exit(1);
1676 	    }
1677 	} else {
1678 	    if ((tpp = (XPoint *) realloc(_pp_, i * sizeof(XPoint))) == 0) {
1679 		file_msg("Can't alloc memory for %d point array",i);
1680 		_noalloc_ = True;
1681 		return False;
1682 	    }
1683 	}
1684 	/* everything ok, set global pointer and count */
1685 	_pp_ = tpp;
1686 	_npp_ = i;
1687     }
1688     return True;
1689 }
1690 
1691 /*
1692  * clip_poly - This procedure performs the Sutherland-Hodgman polygon clipping
1693  * on the inVertices array, putting the resultant points into the outVertices array,
1694  * and returning the number of points as the return value.
1695  * We are clipping to the canvas area.
1696  */
1697 
1698 static int
clip_poly(XPoint * inVertices,int npoints,XPoint * outVertices)1699 clip_poly(XPoint *inVertices, int npoints, XPoint *outVertices)
1700 {
1701 	/* clip to left edge */
1702         npoints = SutherlandHodgmanPolygoClip (inVertices, outVertices, npoints,
1703 					-100, CANVAS_HT*2, -100, -100);
1704         setup_next(npoints, inVertices, outVertices);
1705 	/* now to bottom edge */
1706         npoints = SutherlandHodgmanPolygoClip (inVertices,outVertices, npoints,
1707 					-100, CANVAS_HT*2, CANVAS_WD*2, CANVAS_HT*2);
1708         setup_next(npoints, inVertices, outVertices);
1709 	/* right edge */
1710         npoints = SutherlandHodgmanPolygoClip (inVertices,outVertices, npoints,
1711 					CANVAS_WD*2, -100, CANVAS_WD*2, CANVAS_HT*2);
1712         setup_next(npoints, inVertices, outVertices);
1713 	/* top edge */
1714         npoints = SutherlandHodgmanPolygoClip (inVertices,outVertices, npoints,
1715 					CANVAS_WD*2, -100, -100, -100);
1716         setup_next(npoints, inVertices, outVertices);
1717         return npoints;
1718 }
1719 
1720 /*
1721  * The "SutherlandHodgmanPolygoClip" function is a critical function of the
1722  * polygon clipping. It uses the Sutherland_Hodgman algorithm to implement
1723  * a step in clipping a polygon to a clipping window.
1724  */
1725 
1726 int
SutherlandHodgmanPolygoClip(XPoint * inVertices,XPoint * outVertices,int inLength,int x1,int y1,int x2,int y2)1727 SutherlandHodgmanPolygoClip (
1728     XPoint	*inVertices,		/* Input vertex array */
1729     XPoint	*outVertices,		/* Output vertex array */
1730     int		 inLength,		/* Number of entries in inVertices */
1731     int		 x1, int y1, int x2, int y2)	/* Edge of clip polygon */
1732 {
1733 	XPoint s,p;	/*Start, end point of current polygon edge*/
1734 	XPoint i;	/*Intersection point with a clip boundary*/
1735 	int j;		/*Vertex loop counter*/
1736 	int outpts;	/* number of points in output array */
1737 
1738         outpts = 0;
1739         s.x = inVertices[inLength-1].x; /*Start with the last vertex in inVertices*/
1740         s.y = inVertices[inLength-1].y;
1741         for (j=0; j < inLength; j++) {
1742             p.x = inVertices[j].x; /*Now s and p correspond to the vertices*/
1743             p.y = inVertices[j].y;
1744             if (inside(p,x1, y1, x2, y2)) {      /*Cases 1 and 4*/
1745                  if (inside(s, x1, y1, x2, y2)) {
1746 			outVertices[outpts].x = p.x;
1747 			outVertices[outpts].y = p.y;
1748 			outpts++;
1749                 } else {                            /*Case 4*/
1750                         intersect(s, p, x1, y1, x2, y2, &i);
1751 			outVertices[outpts].x = i.x;
1752 			outVertices[outpts].y = i.y;
1753 			outpts++;
1754 			outVertices[outpts].x = p.x;
1755 			outVertices[outpts].y = p.y;
1756 			outpts++;
1757                 }
1758             } else {                  /*Cases 2 and 3*/
1759                 if (inside(s, x1, y1, x2, y2))  /*Cases 2*/ {
1760                         intersect(s, p, x1, y1, x2, y2, &i);
1761 			outVertices[outpts].x = i.x;
1762 			outVertices[outpts].y = i.y;
1763 			outpts++;
1764                 }
1765            }                          /*No action for case 3*/
1766            s.x = p.x;	/*Advance to next pair of vertices*/
1767            s.y = p.y;
1768 	}
1769 	return outpts;
1770 }      /*SutherlandHodgmanPolygonClip*/
1771 
1772 /*
1773  * The "Inside" function returns TRUE if the vertex tested is on the inside
1774  * of the clipping boundary. "Inside" is defined as "to the left of
1775  * clipping boundary when one looks from the first vertex to the second
1776  * vertex of the clipping boundary". The code for this function is:
1777  */
1778 
1779 static Boolean
inside(XPoint testVertex,int x1,int y1,int x2,int y2)1780 inside (XPoint testVertex, int x1, int y1, int x2, int y2)
1781 {
1782     if (x2 > x1)              /*bottom edge*/
1783 	if (testVertex.y <= y1)
1784 	    return True;
1785     if (x2 < x1)              /*top edge*/
1786 	if (testVertex.y >= y1)
1787 	    return True;
1788     if (y2 > y1)              /*right edge*/
1789 	if (testVertex.x <= x2)
1790 	    return True;
1791     if (y2 < y1)              /*left edge*/
1792 	if (testVertex.x >= x2)
1793 	    return True;
1794     /* outside */
1795     return False;
1796 }
1797 
1798 /*
1799  * The "intersect" function calculates the intersection of the polygon edge
1800  * (vertex s to p) with the clipping boundary.
1801  */
1802 
1803 static void
intersect(XPoint first,XPoint second,int x1,int y1,int x2,int y2,XPoint * intersectPt)1804 intersect(XPoint first, XPoint second, int x1, int y1, int x2, int y2,
1805                 XPoint *intersectPt)
1806 {
1807   if (y1 == y2) {    /*horizontal*/
1808      intersectPt->y=y1;
1809      intersectPt->x=first.x +(y1-first.y)*
1810                     (second.x-first.x)/(second.y-first.y);   /*Vertical*/
1811    } else {
1812            intersectPt->x=x1;
1813            intersectPt->y=first.y +(x1-first.x)*
1814                     (second.y-first.y)/(second.x-first.x);
1815    }
1816 }
1817 
1818 /*
1819  * setup_next copies the input to the output
1820  */
1821 
1822 static void
setup_next(int npoints,XPoint * in,XPoint * out)1823 setup_next(int npoints, XPoint *in, XPoint *out)
1824 {
1825 	int i;
1826 	for (i=0; i<npoints; i++) {
1827 		in[i].x = out[i].x;
1828 		in[i].y = out[i].y;
1829 	}
1830 }
1831 
1832 
1833 /*
1834  * clip_line - This procedure clips a line to the current clip boundaries and
1835  * returns the new coordinates in x3, y3 and x4, y4.
1836  * If the line lies completely outside of the clip boundary, the result is False,
1837  * otherwise True.
1838  * This procedure uses the well known Cohen-Sutherland line clipping
1839  * algorithm to clip each coordinate.
1840  */
1841 
1842 int compoutcode(int x, int y);
1843 
1844 /* bitfields for output codes */
1845 #define codetop    1
1846 #define codebottom 2
1847 #define coderight  4
1848 #define codeleft   8
1849 
1850 void
clip_line(int x1,int y1,int x2,int y2,short * x3,short * y3,short * x4,short * y4)1851 clip_line(int x1, int y1, int x2, int y2,  short *x3, short *y3, short *x4, short *y4)
1852 {
1853   int outcode0;         /* the code of the first endpoint  */
1854   int outcode1;         /* the code of the second endpoint */
1855   int outcodeout;
1856   int x, y;
1857 
1858   outcode0 = compoutcode(x1, y1);		/* compute the original codes   */
1859   outcode1 = compoutcode(x2, y2);
1860 
1861   /* while not trivially accepted */
1862   while (outcode0 != 0 || outcode1 != 0)  {
1863     if ((outcode0 & outcode1) != 0) {		/* trivial reject */
1864 	/* set line to a single point at the limits of the screen */
1865 	if ((outcode0|outcode1) & codebottom) *y3 = *y4 = CANVAS_HT;
1866 	if ((outcode0|outcode1) & codetop)    *y3 = *y4 = 0;
1867 	if ((outcode0|outcode1) & codeleft)   *x3 = *x4 = 0;
1868 	if ((outcode0|outcode1) & coderight)  *x3 = *x4 = CANVAS_WD;
1869 	return;
1870     } else {
1871 	/* failed both tests, so calculate the line segment to clip */
1872 	if (outcode0 > 0 )
1873 	    outcodeout = outcode0;	/* clip the first point */
1874 	else
1875 	    outcodeout = outcode1;	/* clip the last point  */
1876 
1877 	if ((outcodeout & codebottom) == codebottom) {
1878 	    /* clip the line to the bottom of the viewport     */
1879 	    y = CANVAS_HT;
1880 	    x = x1+(double)(x2-x1)*(double)(y-y1) / (y2 - y1);
1881 	}
1882 	else if ((outcodeout & codetop) == codetop ) {
1883 	    /* clip the line to the top of the viewport        */
1884 	    y = 0;
1885 	    x = x1+(double)(x2-x1)*(double)(y-y1) / (y2 - y1);
1886 	}
1887 	else if ((outcodeout & coderight) == coderight ) {
1888 	    /* clip the line to the right edge of the viewport */
1889 	    x = CANVAS_WD;
1890 	    y = y1+(double)(y2-y1)*(double)(x-x1) / (x2-x1);
1891 	}
1892 	else if ((outcodeout & codeleft) == codeleft ) {
1893 	    /* clip the line to the left edge of the viewport  */
1894 	    x = 0;
1895 	    y = y1+(double)(y2-y1)*(double)(x-x1) / (x2-x1);
1896 	};
1897 
1898 	if (outcodeout == outcode0) {		/* modify the first coordinate   */
1899 	    x1 = x; y1 = y;			/* update temporary variables    */
1900 	    outcode0 = compoutcode(x1, y1);	/* recalculate the outcode       */
1901 	}
1902 	else {
1903 	/* modify the second coordinate  */
1904 	    x2 = x; y2 = y;			/* update temporary variables    */
1905 	    outcode1 = compoutcode(x2, y2);	/* recalculate the outcode       */
1906 	}
1907     }
1908   }
1909 
1910   /* coordinates for the new line! */
1911   *x3 = (short) x1;
1912   *y3 = (short) y1;
1913   *x4 = (short) x2;
1914   *y4 = (short) y2;
1915 
1916   return;
1917 }
1918 
1919 /* return codes for different cases */
1920 
1921 int
compoutcode(int x,int y)1922 compoutcode(int x, int y)
1923 {
1924   int code = 0;
1925 
1926   if      (y > CANVAS_HT) code = codebottom;
1927   else if (y < 0) code = codetop;
1928 
1929   if      (x > CANVAS_WD) code = code+coderight;
1930   else if (x < 0) code = code+codeleft;
1931   return code;
1932 }
1933 
1934