1*04ac863bSchristos /*	$NetBSD: draw.c,v 1.1.1.1 2016/01/13 18:41:49 christos Exp $	*/
2*04ac863bSchristos 
3*04ac863bSchristos /*
4*04ac863bSchristos  * draw.c
5*04ac863bSchristos  *
6*04ac863bSchristos  * accept dvi function calls and translate to X
7*04ac863bSchristos  */
8*04ac863bSchristos 
9*04ac863bSchristos #include <X11/Xos.h>
10*04ac863bSchristos #include <X11/IntrinsicP.h>
11*04ac863bSchristos #include <X11/StringDefs.h>
12*04ac863bSchristos #include <stdio.h>
13*04ac863bSchristos #include <ctype.h>
14*04ac863bSchristos #include <math.h>
15*04ac863bSchristos 
16*04ac863bSchristos /* math.h on a Sequent doesn't define M_PI, apparently */
17*04ac863bSchristos #ifndef M_PI
18*04ac863bSchristos #define M_PI	3.14159265358979323846
19*04ac863bSchristos #endif
20*04ac863bSchristos 
21*04ac863bSchristos #include "DviP.h"
22*04ac863bSchristos 
23*04ac863bSchristos #define DeviceToX(dw, n) ((int)((n) * (dw)->dvi.scale_factor + .5))
24*04ac863bSchristos #define XPos(dw) (DeviceToX((dw), (dw)->dvi.state->x - \
25*04ac863bSchristos                   (dw)->dvi.text_device_width) + (dw)->dvi.text_x_width)
26*04ac863bSchristos #define YPos(dw) (DeviceToX((dw), (dw)->dvi.state->y))
27*04ac863bSchristos 
28*04ac863bSchristos static int FakeCharacter(DviWidget, char *, int);
29*04ac863bSchristos 
30*04ac863bSchristos /* font.c */
31*04ac863bSchristos extern int MaxFontPosition(DviWidget);
32*04ac863bSchristos 
33*04ac863bSchristos void
HorizontalMove(DviWidget dw,int delta)34*04ac863bSchristos HorizontalMove(DviWidget dw, int delta)
35*04ac863bSchristos {
36*04ac863bSchristos 	dw->dvi.state->x += delta;
37*04ac863bSchristos }
38*04ac863bSchristos 
39*04ac863bSchristos void
HorizontalGoto(DviWidget dw,int NewPosition)40*04ac863bSchristos HorizontalGoto(DviWidget dw, int NewPosition)
41*04ac863bSchristos {
42*04ac863bSchristos 	dw->dvi.state->x = NewPosition;
43*04ac863bSchristos }
44*04ac863bSchristos 
45*04ac863bSchristos void
VerticalMove(DviWidget dw,int delta)46*04ac863bSchristos VerticalMove(DviWidget dw, int delta)
47*04ac863bSchristos {
48*04ac863bSchristos 	dw->dvi.state->y += delta;
49*04ac863bSchristos }
50*04ac863bSchristos 
51*04ac863bSchristos void
VerticalGoto(DviWidget dw,int NewPosition)52*04ac863bSchristos VerticalGoto(DviWidget dw, int NewPosition)
53*04ac863bSchristos {
54*04ac863bSchristos 	dw->dvi.state->y = NewPosition;
55*04ac863bSchristos }
56*04ac863bSchristos 
57*04ac863bSchristos void
AdjustCacheDeltas(DviWidget dw)58*04ac863bSchristos AdjustCacheDeltas (DviWidget dw)
59*04ac863bSchristos {
60*04ac863bSchristos 	int extra;
61*04ac863bSchristos 	int nadj;
62*04ac863bSchristos 	int i;
63*04ac863bSchristos 
64*04ac863bSchristos 	nadj = 0;
65*04ac863bSchristos 	extra = DeviceToX(dw, dw->dvi.text_device_width)
66*04ac863bSchristos 		- dw->dvi.text_x_width;
67*04ac863bSchristos 	if (extra == 0)
68*04ac863bSchristos 		return;
69*04ac863bSchristos 	for (i = 0; i <= dw->dvi.cache.index; i++)
70*04ac863bSchristos 		if (dw->dvi.cache.adjustable[i])
71*04ac863bSchristos 			++nadj;
72*04ac863bSchristos 	dw->dvi.text_x_width += extra;
73*04ac863bSchristos 	if (nadj <= 1)
74*04ac863bSchristos 		return;
75*04ac863bSchristos 	for (i = 0; i <= dw->dvi.cache.index; i++)
76*04ac863bSchristos 		if (dw->dvi.cache.adjustable[i]) {
77*04ac863bSchristos 			int x;
78*04ac863bSchristos 			int *deltap;
79*04ac863bSchristos 
80*04ac863bSchristos 			x = extra/nadj;
81*04ac863bSchristos 			deltap = &dw->dvi.cache.cache[i].delta;
82*04ac863bSchristos #define MIN_DELTA 2
83*04ac863bSchristos 			if (*deltap > 0 && x + *deltap < MIN_DELTA) {
84*04ac863bSchristos 				x = MIN_DELTA - *deltap;
85*04ac863bSchristos 				if (x <= 0)
86*04ac863bSchristos 					*deltap = MIN_DELTA;
87*04ac863bSchristos 				else
88*04ac863bSchristos 					x = 0;
89*04ac863bSchristos 			}
90*04ac863bSchristos 			else
91*04ac863bSchristos 				*deltap += x;
92*04ac863bSchristos 			extra -= x;
93*04ac863bSchristos 			--nadj;
94*04ac863bSchristos 			dw->dvi.cache.adjustable[i] = 0;
95*04ac863bSchristos 		}
96*04ac863bSchristos }
97*04ac863bSchristos 
98*04ac863bSchristos void
FlushCharCache(DviWidget dw)99*04ac863bSchristos FlushCharCache (DviWidget dw)
100*04ac863bSchristos {
101*04ac863bSchristos 	if (dw->dvi.cache.char_index != 0) {
102*04ac863bSchristos 		AdjustCacheDeltas (dw);
103*04ac863bSchristos 		XDrawText (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
104*04ac863bSchristos 			   dw->dvi.cache.start_x, dw->dvi.cache.start_y,
105*04ac863bSchristos 			   dw->dvi.cache.cache, dw->dvi.cache.index + 1);
106*04ac863bSchristos 	}
107*04ac863bSchristos 	dw->dvi.cache.index = 0;
108*04ac863bSchristos 	dw->dvi.cache.max = DVI_TEXT_CACHE_SIZE;
109*04ac863bSchristos #if 0
110*04ac863bSchristos 	if (dw->dvi.noPolyText)
111*04ac863bSchristos 	    dw->dvi.cache.max = 1;
112*04ac863bSchristos #endif
113*04ac863bSchristos 	dw->dvi.cache.char_index = 0;
114*04ac863bSchristos 	dw->dvi.cache.cache[0].nchars = 0;
115*04ac863bSchristos 	dw->dvi.cache.start_x = dw->dvi.cache.x	= XPos (dw);
116*04ac863bSchristos 	dw->dvi.cache.start_y = dw->dvi.cache.y = YPos (dw);
117*04ac863bSchristos }
118*04ac863bSchristos 
119*04ac863bSchristos void
Newline(DviWidget dw)120*04ac863bSchristos Newline (DviWidget dw)
121*04ac863bSchristos {
122*04ac863bSchristos 	FlushCharCache (dw);
123*04ac863bSchristos 	dw->dvi.text_x_width = dw->dvi.text_device_width = 0;
124*04ac863bSchristos 	dw->dvi.word_flag = 0;
125*04ac863bSchristos }
126*04ac863bSchristos 
127*04ac863bSchristos void
Word(DviWidget dw)128*04ac863bSchristos Word (DviWidget dw)
129*04ac863bSchristos {
130*04ac863bSchristos 	dw->dvi.word_flag = 1;
131*04ac863bSchristos }
132*04ac863bSchristos 
133*04ac863bSchristos #define charWidth(fi,c) (\
134*04ac863bSchristos     (fi)->per_char ?\
135*04ac863bSchristos 	(fi)->per_char[(c) - (fi)->min_char_or_byte2].width\
136*04ac863bSchristos     :\
137*04ac863bSchristos 	(fi)->max_bounds.width\
138*04ac863bSchristos )
139*04ac863bSchristos 
140*04ac863bSchristos 
141*04ac863bSchristos static
charExists(XFontStruct * fi,int c)142*04ac863bSchristos int charExists (XFontStruct *fi, int c)
143*04ac863bSchristos {
144*04ac863bSchristos 	XCharStruct *p;
145*04ac863bSchristos 
146*04ac863bSchristos 	/* `c' is always >= 0 */
147*04ac863bSchristos 	if (fi->per_char == NULL
148*04ac863bSchristos 	    || (unsigned int)c < fi->min_char_or_byte2
149*04ac863bSchristos 	    || (unsigned int)c > fi->max_char_or_byte2)
150*04ac863bSchristos 		return 0;
151*04ac863bSchristos 	p = fi->per_char + (c - fi->min_char_or_byte2);
152*04ac863bSchristos 	return (p->lbearing != 0 || p->rbearing != 0 || p->width != 0
153*04ac863bSchristos 		|| p->ascent != 0 || p->descent != 0 || p->attributes != 0);
154*04ac863bSchristos }
155*04ac863bSchristos 
156*04ac863bSchristos /* `wid' is in device units */
157*04ac863bSchristos static void
DoCharacter(DviWidget dw,int c,int wid)158*04ac863bSchristos DoCharacter (DviWidget dw, int c, int wid)
159*04ac863bSchristos {
160*04ac863bSchristos 	register XFontStruct	*font;
161*04ac863bSchristos 	register XTextItem	*text;
162*04ac863bSchristos 	int	x, y;
163*04ac863bSchristos 
164*04ac863bSchristos 	x = XPos(dw);
165*04ac863bSchristos 	y = YPos(dw);
166*04ac863bSchristos 
167*04ac863bSchristos 	/*
168*04ac863bSchristos 	 * quick and dirty extents calculation:
169*04ac863bSchristos 	 */
170*04ac863bSchristos 	if (!(y + 24 >= dw->dvi.extents.y1
171*04ac863bSchristos 	      && y - 24 <= dw->dvi.extents.y2
172*04ac863bSchristos #if 0
173*04ac863bSchristos 	      && x + 24 >= dw->dvi.extents.x1
174*04ac863bSchristos 	      && x - 24 <= dw->dvi.extents.x2
175*04ac863bSchristos #endif
176*04ac863bSchristos 	    ))
177*04ac863bSchristos 		return;
178*04ac863bSchristos 
179*04ac863bSchristos 	if (y != dw->dvi.cache.y
180*04ac863bSchristos 	    || dw->dvi.cache.char_index >= DVI_CHAR_CACHE_SIZE) {
181*04ac863bSchristos 		FlushCharCache (dw);
182*04ac863bSchristos 		x = dw->dvi.cache.x;
183*04ac863bSchristos 		dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0;
184*04ac863bSchristos 	}
185*04ac863bSchristos 	/*
186*04ac863bSchristos 	 * load a new font, if the current block is not empty,
187*04ac863bSchristos 	 * step to the next.
188*04ac863bSchristos 	 */
189*04ac863bSchristos 	if (dw->dvi.cache.font_size != dw->dvi.state->font_size ||
190*04ac863bSchristos 	    dw->dvi.cache.font_number != dw->dvi.state->font_number)
191*04ac863bSchristos 	{
192*04ac863bSchristos 		FlushCharCache (dw);
193*04ac863bSchristos 		x = dw->dvi.cache.x;
194*04ac863bSchristos 		dw->dvi.cache.font_size = dw->dvi.state->font_size;
195*04ac863bSchristos 		dw->dvi.cache.font_number = dw->dvi.state->font_number;
196*04ac863bSchristos 		dw->dvi.cache.font = QueryFont (dw,
197*04ac863bSchristos 						dw->dvi.cache.font_number,
198*04ac863bSchristos 						dw->dvi.cache.font_size);
199*04ac863bSchristos 		if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
200*04ac863bSchristos 			++dw->dvi.cache.index;
201*04ac863bSchristos 			if (dw->dvi.cache.index >= dw->dvi.cache.max)
202*04ac863bSchristos 				FlushCharCache (dw);
203*04ac863bSchristos 			dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
204*04ac863bSchristos 			dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0;
205*04ac863bSchristos 		}
206*04ac863bSchristos 	}
207*04ac863bSchristos 	if (x != dw->dvi.cache.x || dw->dvi.word_flag) {
208*04ac863bSchristos 		if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
209*04ac863bSchristos 			++dw->dvi.cache.index;
210*04ac863bSchristos 			if (dw->dvi.cache.index >= dw->dvi.cache.max)
211*04ac863bSchristos 				FlushCharCache (dw);
212*04ac863bSchristos 			dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
213*04ac863bSchristos 			dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0;
214*04ac863bSchristos 		}
215*04ac863bSchristos 		dw->dvi.cache.adjustable[dw->dvi.cache.index]
216*04ac863bSchristos 			= dw->dvi.word_flag;
217*04ac863bSchristos 		dw->dvi.word_flag = 0;
218*04ac863bSchristos 	}
219*04ac863bSchristos 	font = dw->dvi.cache.font;
220*04ac863bSchristos 	text = &dw->dvi.cache.cache[dw->dvi.cache.index];
221*04ac863bSchristos 	if (text->nchars == 0) {
222*04ac863bSchristos 		text->chars = &dw->dvi.cache.char_cache[dw->dvi.cache.char_index];
223*04ac863bSchristos 		text->delta = x - dw->dvi.cache.x;
224*04ac863bSchristos 		if (font != dw->dvi.font) {
225*04ac863bSchristos 			text->font = font->fid;
226*04ac863bSchristos 			dw->dvi.font = font;
227*04ac863bSchristos 		} else
228*04ac863bSchristos 			text->font = None;
229*04ac863bSchristos 		dw->dvi.cache.x += text->delta;
230*04ac863bSchristos 	}
231*04ac863bSchristos 	if (charExists(font, c)) {
232*04ac863bSchristos 		int w;
233*04ac863bSchristos 		dw->dvi.cache.char_cache[dw->dvi.cache.char_index++] = (char) c;
234*04ac863bSchristos 		++text->nchars;
235*04ac863bSchristos 		w = charWidth(font, c);
236*04ac863bSchristos 		dw->dvi.cache.x += w;
237*04ac863bSchristos 		if (wid != 0) {
238*04ac863bSchristos 			dw->dvi.text_x_width += w;
239*04ac863bSchristos 			dw->dvi.text_device_width += wid;
240*04ac863bSchristos 		}
241*04ac863bSchristos 	}
242*04ac863bSchristos }
243*04ac863bSchristos 
244*04ac863bSchristos static
FindCharWidth(DviWidget dw,char * buf,int * widp)245*04ac863bSchristos int FindCharWidth (DviWidget dw, char *buf, int *widp)
246*04ac863bSchristos {
247*04ac863bSchristos 	int maxpos;
248*04ac863bSchristos 	int i;
249*04ac863bSchristos 
250*04ac863bSchristos 	if (dw->dvi.device_font == 0
251*04ac863bSchristos 	    || dw->dvi.state->font_number != dw->dvi.device_font_number) {
252*04ac863bSchristos 		dw->dvi.device_font_number = dw->dvi.state->font_number;
253*04ac863bSchristos 		dw->dvi.device_font
254*04ac863bSchristos 			= QueryDeviceFont (dw, dw->dvi.device_font_number);
255*04ac863bSchristos 	}
256*04ac863bSchristos 	if (dw->dvi.device_font
257*04ac863bSchristos 	    && device_char_width (dw->dvi.device_font,
258*04ac863bSchristos 				  dw->dvi.state->font_size, buf, widp))
259*04ac863bSchristos 		return 1;
260*04ac863bSchristos 
261*04ac863bSchristos 	maxpos = MaxFontPosition (dw);
262*04ac863bSchristos 	for (i = 1; i <= maxpos; i++) {
263*04ac863bSchristos 		DeviceFont *f = QueryDeviceFont (dw, i);
264*04ac863bSchristos 		if (f && device_font_special (f)
265*04ac863bSchristos 		    && device_char_width (f, dw->dvi.state->font_size,
266*04ac863bSchristos 					  buf, widp)) {
267*04ac863bSchristos 			dw->dvi.state->font_number = i;
268*04ac863bSchristos 			return 1;
269*04ac863bSchristos 		}
270*04ac863bSchristos 	}
271*04ac863bSchristos 	return 0;
272*04ac863bSchristos }
273*04ac863bSchristos 
274*04ac863bSchristos /* Return the width of the character in device units. */
275*04ac863bSchristos 
PutCharacter(DviWidget dw,char * buf)276*04ac863bSchristos int PutCharacter (DviWidget dw, char *buf)
277*04ac863bSchristos {
278*04ac863bSchristos 	int		prevFont;
279*04ac863bSchristos 	int		c = -1;
280*04ac863bSchristos 	int		wid = 0;
281*04ac863bSchristos 	DviCharNameMap	*map;
282*04ac863bSchristos 
283*04ac863bSchristos 	if (!dw->dvi.display_enable)
284*04ac863bSchristos 		return 0;	/* The width doesn't matter in this case. */
285*04ac863bSchristos 	prevFont = dw->dvi.state->font_number;
286*04ac863bSchristos 	if (!FindCharWidth (dw, buf, &wid))
287*04ac863bSchristos 		return 0;
288*04ac863bSchristos 	map = QueryFontMap (dw, dw->dvi.state->font_number);
289*04ac863bSchristos 	if (map)
290*04ac863bSchristos 		c = DviCharIndex (map, buf);
291*04ac863bSchristos 	if (c >= 0)
292*04ac863bSchristos 		DoCharacter (dw, c, wid);
293*04ac863bSchristos 	else
294*04ac863bSchristos 		(void) FakeCharacter (dw, buf, wid);
295*04ac863bSchristos 	dw->dvi.state->font_number = prevFont;
296*04ac863bSchristos 	return wid;
297*04ac863bSchristos }
298*04ac863bSchristos 
299*04ac863bSchristos /* Return 1 if we can fake it; 0 otherwise. */
300*04ac863bSchristos 
301*04ac863bSchristos static
FakeCharacter(DviWidget dw,char * buf,int wid)302*04ac863bSchristos int FakeCharacter (DviWidget dw, char *buf, int wid)
303*04ac863bSchristos {
304*04ac863bSchristos 	int oldx, oldw;
305*04ac863bSchristos 	char ch[2];
306*04ac863bSchristos 	const char *chars = 0;
307*04ac863bSchristos 
308*04ac863bSchristos 	if (buf[0] == '\0' || buf[1] == '\0' || buf[2] != '\0')
309*04ac863bSchristos 		return 0;
310*04ac863bSchristos #define pack2(c1, c2) (((c1) << 8) | (c2))
311*04ac863bSchristos 
312*04ac863bSchristos 	switch (pack2(buf[0], buf[1])) {
313*04ac863bSchristos 	case pack2('f', 'i'):
314*04ac863bSchristos 		chars = "fi";
315*04ac863bSchristos 		break;
316*04ac863bSchristos 	case pack2('f', 'l'):
317*04ac863bSchristos 		chars = "fl";
318*04ac863bSchristos 		break;
319*04ac863bSchristos 	case pack2('f', 'f'):
320*04ac863bSchristos 		chars = "ff";
321*04ac863bSchristos 		break;
322*04ac863bSchristos 	case pack2('F', 'i'):
323*04ac863bSchristos 		chars = "ffi";
324*04ac863bSchristos 		break;
325*04ac863bSchristos 	case pack2('F', 'l'):
326*04ac863bSchristos 		chars = "ffl";
327*04ac863bSchristos 		break;
328*04ac863bSchristos 	}
329*04ac863bSchristos 	if (!chars)
330*04ac863bSchristos 		return 0;
331*04ac863bSchristos 	oldx = dw->dvi.state->x;
332*04ac863bSchristos 	oldw = dw->dvi.text_device_width;
333*04ac863bSchristos 	ch[1] = '\0';
334*04ac863bSchristos 	for (; *chars; chars++) {
335*04ac863bSchristos 		ch[0] = *chars;
336*04ac863bSchristos 		dw->dvi.state->x += PutCharacter (dw, ch);
337*04ac863bSchristos 	}
338*04ac863bSchristos 	dw->dvi.state->x = oldx;
339*04ac863bSchristos 	dw->dvi.text_device_width = oldw + wid;
340*04ac863bSchristos 	return 1;
341*04ac863bSchristos }
342*04ac863bSchristos 
343*04ac863bSchristos void
PutNumberedCharacter(DviWidget dw,int c)344*04ac863bSchristos PutNumberedCharacter (DviWidget dw, int c)
345*04ac863bSchristos {
346*04ac863bSchristos 	char *name;
347*04ac863bSchristos 	int wid;
348*04ac863bSchristos 	DviCharNameMap	*map;
349*04ac863bSchristos 
350*04ac863bSchristos 	if (!dw->dvi.display_enable)
351*04ac863bSchristos 		return;
352*04ac863bSchristos 
353*04ac863bSchristos 	if (dw->dvi.device_font == 0
354*04ac863bSchristos 	    || dw->dvi.state->font_number != dw->dvi.device_font_number) {
355*04ac863bSchristos 		dw->dvi.device_font_number = dw->dvi.state->font_number;
356*04ac863bSchristos 		dw->dvi.device_font
357*04ac863bSchristos 			= QueryDeviceFont (dw, dw->dvi.device_font_number);
358*04ac863bSchristos 	}
359*04ac863bSchristos 
360*04ac863bSchristos 	if (dw->dvi.device_font == 0
361*04ac863bSchristos 	    || !device_code_width (dw->dvi.device_font,
362*04ac863bSchristos 				   dw->dvi.state->font_size, c, &wid))
363*04ac863bSchristos 		return;
364*04ac863bSchristos 	if (dw->dvi.native) {
365*04ac863bSchristos 		DoCharacter (dw, c, wid);
366*04ac863bSchristos 		return;
367*04ac863bSchristos 	}
368*04ac863bSchristos 	map = QueryFontMap (dw, dw->dvi.state->font_number);
369*04ac863bSchristos 	if (!map)
370*04ac863bSchristos 		return;
371*04ac863bSchristos 	for (name = device_name_for_code (dw->dvi.device_font, c);
372*04ac863bSchristos 	     name;
373*04ac863bSchristos 	     name = device_name_for_code ((DeviceFont *)0, c)) {
374*04ac863bSchristos 		int code = DviCharIndex (map, name);
375*04ac863bSchristos 		if (code >= 0) {
376*04ac863bSchristos 			DoCharacter (dw, code, wid);
377*04ac863bSchristos 			break;
378*04ac863bSchristos 		}
379*04ac863bSchristos 		if (FakeCharacter (dw, name, wid))
380*04ac863bSchristos 			break;
381*04ac863bSchristos 	}
382*04ac863bSchristos }
383*04ac863bSchristos 
384*04ac863bSchristos void
ClearPage(DviWidget dw)385*04ac863bSchristos ClearPage (DviWidget dw)
386*04ac863bSchristos {
387*04ac863bSchristos 	XClearWindow (XtDisplay (dw), XtWindow (dw));
388*04ac863bSchristos }
389*04ac863bSchristos 
390*04ac863bSchristos static void
setGC(DviWidget dw)391*04ac863bSchristos setGC (DviWidget dw)
392*04ac863bSchristos {
393*04ac863bSchristos 	int desired_line_width;
394*04ac863bSchristos 
395*04ac863bSchristos 	if (dw->dvi.line_thickness < 0)
396*04ac863bSchristos 		desired_line_width = (int)(((double)dw->dvi.device_resolution
397*04ac863bSchristos 					    * dw->dvi.state->font_size)
398*04ac863bSchristos 					   / (10.0*72.0*dw->dvi.sizescale));
399*04ac863bSchristos 	else
400*04ac863bSchristos 		desired_line_width = dw->dvi.line_thickness;
401*04ac863bSchristos 
402*04ac863bSchristos 	if (desired_line_width != dw->dvi.line_width) {
403*04ac863bSchristos 		XGCValues values;
404*04ac863bSchristos 		values.line_width = DeviceToX(dw, desired_line_width);
405*04ac863bSchristos 		if (values.line_width == 0)
406*04ac863bSchristos 			values.line_width = 1;
407*04ac863bSchristos 		XChangeGC(XtDisplay (dw), dw->dvi.normal_GC,
408*04ac863bSchristos 			  GCLineWidth, &values);
409*04ac863bSchristos 		dw->dvi.line_width = desired_line_width;
410*04ac863bSchristos 	}
411*04ac863bSchristos }
412*04ac863bSchristos 
413*04ac863bSchristos static void
setFillGC(DviWidget dw)414*04ac863bSchristos setFillGC (DviWidget dw)
415*04ac863bSchristos {
416*04ac863bSchristos 	int fill_type;
417*04ac863bSchristos 	unsigned long mask = GCFillStyle | GCForeground;
418*04ac863bSchristos 
419*04ac863bSchristos 	fill_type = (dw->dvi.fill * 10) / (DVI_FILL_MAX + 1);
420*04ac863bSchristos 	if (dw->dvi.fill_type != fill_type) {
421*04ac863bSchristos 		XGCValues values;
422*04ac863bSchristos 		if (fill_type <= 0) {
423*04ac863bSchristos 			values.foreground = dw->dvi.background;
424*04ac863bSchristos 			values.fill_style = FillSolid;
425*04ac863bSchristos 		} else if (fill_type >= 9) {
426*04ac863bSchristos 			values.foreground = dw->dvi.foreground;
427*04ac863bSchristos 			values.fill_style = FillSolid;
428*04ac863bSchristos 		} else {
429*04ac863bSchristos 			values.foreground = dw->dvi.foreground;
430*04ac863bSchristos 			values.fill_style = FillOpaqueStippled;
431*04ac863bSchristos 			values.stipple = dw->dvi.gray[fill_type - 1];
432*04ac863bSchristos 			mask |= GCStipple;
433*04ac863bSchristos 		}
434*04ac863bSchristos 		XChangeGC(XtDisplay (dw), dw->dvi.fill_GC, mask, &values);
435*04ac863bSchristos 		dw->dvi.fill_type = fill_type;
436*04ac863bSchristos 	}
437*04ac863bSchristos }
438*04ac863bSchristos 
439*04ac863bSchristos void
DrawLine(DviWidget dw,int x,int y)440*04ac863bSchristos DrawLine (DviWidget dw, int x, int y)
441*04ac863bSchristos {
442*04ac863bSchristos 	int xp, yp;
443*04ac863bSchristos 
444*04ac863bSchristos 	AdjustCacheDeltas (dw);
445*04ac863bSchristos 	setGC (dw);
446*04ac863bSchristos 	xp = XPos (dw);
447*04ac863bSchristos 	yp = YPos (dw);
448*04ac863bSchristos 	XDrawLine (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
449*04ac863bSchristos 		   xp, yp,
450*04ac863bSchristos 		   xp + DeviceToX (dw, x), yp + DeviceToX (dw, y));
451*04ac863bSchristos }
452*04ac863bSchristos 
453*04ac863bSchristos void
DrawCircle(DviWidget dw,int diam)454*04ac863bSchristos DrawCircle (DviWidget dw, int diam)
455*04ac863bSchristos {
456*04ac863bSchristos 	int d;
457*04ac863bSchristos 
458*04ac863bSchristos 	AdjustCacheDeltas (dw);
459*04ac863bSchristos 	setGC (dw);
460*04ac863bSchristos 	d = DeviceToX (dw, diam);
461*04ac863bSchristos 	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
462*04ac863bSchristos 		  XPos (dw), YPos (dw) - d/2,
463*04ac863bSchristos 		  d, d, 0, 64*360);
464*04ac863bSchristos }
465*04ac863bSchristos 
466*04ac863bSchristos void
DrawFilledCircle(DviWidget dw,int diam)467*04ac863bSchristos DrawFilledCircle (DviWidget dw, int diam)
468*04ac863bSchristos {
469*04ac863bSchristos 	int d;
470*04ac863bSchristos 
471*04ac863bSchristos 	AdjustCacheDeltas (dw);
472*04ac863bSchristos 	setFillGC (dw);
473*04ac863bSchristos 	d = DeviceToX (dw, diam);
474*04ac863bSchristos 	XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
475*04ac863bSchristos 		  XPos (dw), YPos (dw) - d/2,
476*04ac863bSchristos 		  d, d, 0, 64*360);
477*04ac863bSchristos 	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
478*04ac863bSchristos 		  XPos (dw), YPos (dw) - d/2,
479*04ac863bSchristos 		  d, d, 0, 64*360);
480*04ac863bSchristos }
481*04ac863bSchristos 
482*04ac863bSchristos void
DrawEllipse(DviWidget dw,int a,int b)483*04ac863bSchristos DrawEllipse (DviWidget dw, int a, int b)
484*04ac863bSchristos {
485*04ac863bSchristos 	AdjustCacheDeltas (dw);
486*04ac863bSchristos 	setGC (dw);
487*04ac863bSchristos 	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
488*04ac863bSchristos 		  XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
489*04ac863bSchristos 		  DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
490*04ac863bSchristos }
491*04ac863bSchristos 
492*04ac863bSchristos void
DrawFilledEllipse(DviWidget dw,int a,int b)493*04ac863bSchristos DrawFilledEllipse (DviWidget dw, int a, int b)
494*04ac863bSchristos {
495*04ac863bSchristos 	AdjustCacheDeltas (dw);
496*04ac863bSchristos 	setFillGC (dw);
497*04ac863bSchristos 	XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
498*04ac863bSchristos 		  XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
499*04ac863bSchristos 		  DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
500*04ac863bSchristos 	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
501*04ac863bSchristos 		  XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
502*04ac863bSchristos 		  DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
503*04ac863bSchristos }
504*04ac863bSchristos 
505*04ac863bSchristos void
DrawArc(DviWidget dw,int x_0,int y_0,int x_1,int y_1)506*04ac863bSchristos DrawArc (DviWidget dw, int x_0, int y_0, int x_1, int y_1)
507*04ac863bSchristos {
508*04ac863bSchristos 	int angle1, angle2;
509*04ac863bSchristos 	int rad = (int)((sqrt ((double)x_0*x_0 + (double)y_0*y_0)
510*04ac863bSchristos 			 + sqrt ((double)x_1*x_1 + (double)y_1*y_1)
511*04ac863bSchristos 			 + 1.0)/2.0);
512*04ac863bSchristos 	if ((x_0 == 0 && y_0 == 0) || (x_1 == 0 && y_1 == 0))
513*04ac863bSchristos 		return;
514*04ac863bSchristos 	angle1 = (int)(atan2 ((double)y_0, (double)-x_0)*180.0*64.0/M_PI);
515*04ac863bSchristos 	angle2 = (int)(atan2 ((double)-y_1, (double)x_1)*180.0*64.0/M_PI);
516*04ac863bSchristos 
517*04ac863bSchristos 	angle2 -= angle1;
518*04ac863bSchristos 	if (angle2 < 0)
519*04ac863bSchristos 		angle2 += 64*360;
520*04ac863bSchristos 
521*04ac863bSchristos 	AdjustCacheDeltas (dw);
522*04ac863bSchristos 	setGC (dw);
523*04ac863bSchristos 
524*04ac863bSchristos 	rad = DeviceToX (dw, rad);
525*04ac863bSchristos 	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
526*04ac863bSchristos 		  XPos (dw) + DeviceToX (dw, x_0) - rad,
527*04ac863bSchristos 		  YPos (dw) + DeviceToX (dw, y_0) - rad,
528*04ac863bSchristos 		  rad*2, rad*2, angle1, angle2);
529*04ac863bSchristos }
530*04ac863bSchristos 
531*04ac863bSchristos void
DrawPolygon(DviWidget dw,int * v,int n)532*04ac863bSchristos DrawPolygon (DviWidget dw, int *v, int n)
533*04ac863bSchristos {
534*04ac863bSchristos 	XPoint *p;
535*04ac863bSchristos 	int i;
536*04ac863bSchristos 	int dx, dy;
537*04ac863bSchristos 
538*04ac863bSchristos 	n /= 2;
539*04ac863bSchristos 
540*04ac863bSchristos 	AdjustCacheDeltas (dw);
541*04ac863bSchristos 	setGC (dw);
542*04ac863bSchristos 	p = (XPoint *)XtMalloc((n + 2)*sizeof(XPoint));
543*04ac863bSchristos 	p[0].x = XPos (dw);
544*04ac863bSchristos 	p[0].y = YPos (dw);
545*04ac863bSchristos 	dx = 0;
546*04ac863bSchristos 	dy = 0;
547*04ac863bSchristos 	for (i = 0; i < n; i++) {
548*04ac863bSchristos 		dx += v[2*i];
549*04ac863bSchristos 		p[i + 1].x = DeviceToX (dw, dx) + p[0].x;
550*04ac863bSchristos 		dy += v[2*i + 1];
551*04ac863bSchristos 		p[i + 1].y = DeviceToX (dw, dy) + p[0].y;
552*04ac863bSchristos 	}
553*04ac863bSchristos 	p[n+1].x = p[0].x;
554*04ac863bSchristos 	p[n+1].y = p[0].y;
555*04ac863bSchristos 	XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
556*04ac863bSchristos 		   p, n + 2, CoordModeOrigin);
557*04ac863bSchristos 	XtFree((char *)p);
558*04ac863bSchristos }
559*04ac863bSchristos 
560*04ac863bSchristos void
DrawFilledPolygon(DviWidget dw,int * v,int n)561*04ac863bSchristos DrawFilledPolygon (DviWidget dw, int *v, int n)
562*04ac863bSchristos {
563*04ac863bSchristos 	XPoint *p;
564*04ac863bSchristos 	int i;
565*04ac863bSchristos 	int dx, dy;
566*04ac863bSchristos 
567*04ac863bSchristos 	n /= 2;
568*04ac863bSchristos 	if (n < 2)
569*04ac863bSchristos 		return;
570*04ac863bSchristos 
571*04ac863bSchristos 	AdjustCacheDeltas (dw);
572*04ac863bSchristos 	setFillGC (dw);
573*04ac863bSchristos 	p = (XPoint *)XtMalloc((n + 2)*sizeof(XPoint));
574*04ac863bSchristos 	p[0].x = p[n+1].x = XPos (dw);
575*04ac863bSchristos 	p[0].y = p[n+1].y = YPos (dw);
576*04ac863bSchristos 	dx = 0;
577*04ac863bSchristos 	dy = 0;
578*04ac863bSchristos 	for (i = 0; i < n; i++) {
579*04ac863bSchristos 		dx += v[2*i];
580*04ac863bSchristos 		p[i + 1].x = DeviceToX (dw, dx) + p[0].x;
581*04ac863bSchristos 		dy += v[2*i + 1];
582*04ac863bSchristos 		p[i + 1].y = DeviceToX (dw, dy) + p[0].y;
583*04ac863bSchristos 	}
584*04ac863bSchristos 	XFillPolygon (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
585*04ac863bSchristos 		      p, n + 1, Complex, CoordModeOrigin);
586*04ac863bSchristos 	XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
587*04ac863bSchristos 		      p, n + 2, CoordModeOrigin);
588*04ac863bSchristos 	XtFree((char *)p);
589*04ac863bSchristos }
590*04ac863bSchristos 
591*04ac863bSchristos #define POINTS_MAX 10000
592*04ac863bSchristos 
593*04ac863bSchristos static void
appendPoint(XPoint * points,int * pointi,int x,int y)594*04ac863bSchristos appendPoint(XPoint *points, int *pointi, int x, int y)
595*04ac863bSchristos {
596*04ac863bSchristos 	if (*pointi < POINTS_MAX) {
597*04ac863bSchristos 		points[*pointi].x = x;
598*04ac863bSchristos 		points[*pointi].y = y;
599*04ac863bSchristos 		*pointi += 1;
600*04ac863bSchristos 	}
601*04ac863bSchristos }
602*04ac863bSchristos 
603*04ac863bSchristos #define FLATNESS 1
604*04ac863bSchristos 
605*04ac863bSchristos static void
flattenCurve(XPoint * points,int * pointi,int x_2,int y_2,int x_3,int y_3,int x_4,int y_4)606*04ac863bSchristos flattenCurve(XPoint *points, int *pointi,
607*04ac863bSchristos 	     int x_2, int y_2, int x_3, int y_3, int x_4, int y_4)
608*04ac863bSchristos {
609*04ac863bSchristos 	int x_1, y_1, dx, dy, n1, n2, n;
610*04ac863bSchristos 
611*04ac863bSchristos 	x_1 = points[*pointi - 1].x;
612*04ac863bSchristos 	y_1 = points[*pointi - 1].y;
613*04ac863bSchristos 
614*04ac863bSchristos 	dx = x_4 - x_1;
615*04ac863bSchristos 	dy = y_4 - y_1;
616*04ac863bSchristos 
617*04ac863bSchristos 	n1 = dy*(x_2 - x_1) - dx*(y_2 - y_1);
618*04ac863bSchristos 	n2 = dy*(x_3 - x_1) - dx*(y_3 - y_1);
619*04ac863bSchristos 	if (n1 < 0)
620*04ac863bSchristos 		n1 = -n1;
621*04ac863bSchristos 	if (n2 < 0)
622*04ac863bSchristos 		n2 = -n2;
623*04ac863bSchristos 	n = n1 > n2 ? n1 : n2;
624*04ac863bSchristos 
625*04ac863bSchristos 	if (n*n / (dy*dy + dx*dx) <= FLATNESS*FLATNESS)
626*04ac863bSchristos 		appendPoint (points, pointi, x_4, y_4);
627*04ac863bSchristos 	else {
628*04ac863bSchristos 		flattenCurve (points, pointi,
629*04ac863bSchristos 			      (x_1 + x_2)/2,
630*04ac863bSchristos 			      (y_1 + y_2)/2,
631*04ac863bSchristos 			      (x_1 + x_2*2 + x_3)/4,
632*04ac863bSchristos 			      (y_1 + y_2*2 + y_3)/4,
633*04ac863bSchristos 			      (x_1 + 3*x_2 + 3*x_3 + x_4)/8,
634*04ac863bSchristos 			      (y_1 + 3*y_2 + 3*y_3 + y_4)/8);
635*04ac863bSchristos 		flattenCurve (points, pointi,
636*04ac863bSchristos 			      (x_2 + x_3*2 + x_4)/4,
637*04ac863bSchristos 			      (y_2 + y_3*2 + y_4)/4,
638*04ac863bSchristos 			      (x_3 + x_4)/2,
639*04ac863bSchristos 			      (y_3 + y_4)/2,
640*04ac863bSchristos 			      x_4,
641*04ac863bSchristos 			      y_4);
642*04ac863bSchristos 	}
643*04ac863bSchristos }
644*04ac863bSchristos 
645*04ac863bSchristos void
DrawSpline(DviWidget dw,int * v,int n)646*04ac863bSchristos DrawSpline (DviWidget dw, int *v, int n)
647*04ac863bSchristos {
648*04ac863bSchristos 	int sx, sy, tx, ty;
649*04ac863bSchristos 	int ox, oy, dx, dy;
650*04ac863bSchristos 	int i;
651*04ac863bSchristos 	int pointi;
652*04ac863bSchristos 	XPoint points[POINTS_MAX];
653*04ac863bSchristos 
654*04ac863bSchristos 	if (n == 0 || (n & 1) != 0)
655*04ac863bSchristos 		return;
656*04ac863bSchristos 	AdjustCacheDeltas (dw);
657*04ac863bSchristos 	setGC (dw);
658*04ac863bSchristos 	ox = XPos (dw);
659*04ac863bSchristos 	oy = YPos (dw);
660*04ac863bSchristos 	dx = v[0];
661*04ac863bSchristos 	dy = v[1];
662*04ac863bSchristos 	sx = ox;
663*04ac863bSchristos 	sy = oy;
664*04ac863bSchristos 	tx = sx + DeviceToX (dw, dx);
665*04ac863bSchristos 	ty = sy + DeviceToX (dw, dy);
666*04ac863bSchristos 
667*04ac863bSchristos 	pointi = 0;
668*04ac863bSchristos 
669*04ac863bSchristos 	appendPoint (points, &pointi, sx, sy);
670*04ac863bSchristos 	appendPoint (points, &pointi, (sx + tx)/2, (sy + ty)/2);
671*04ac863bSchristos 
672*04ac863bSchristos 	for (i = 2; i < n; i += 2) {
673*04ac863bSchristos 		int ux = ox + DeviceToX (dw, dx += v[i]);
674*04ac863bSchristos 		int uy = oy + DeviceToX (dw, dy += v[i+1]);
675*04ac863bSchristos 		flattenCurve (points, &pointi,
676*04ac863bSchristos 			       (sx + tx*5)/6, (sy + ty*5)/6,
677*04ac863bSchristos 			       (tx*5 + ux)/6, (ty*5 + uy)/6,
678*04ac863bSchristos 			       (tx + ux)/2, (ty + uy)/2);
679*04ac863bSchristos 		sx = tx;
680*04ac863bSchristos 		sy = ty;
681*04ac863bSchristos 		tx = ux;
682*04ac863bSchristos 		ty = uy;
683*04ac863bSchristos 	}
684*04ac863bSchristos 
685*04ac863bSchristos 	appendPoint (points, &pointi, tx, ty);
686*04ac863bSchristos 
687*04ac863bSchristos 	XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
688*04ac863bSchristos 		   points, pointi, CoordModeOrigin);
689*04ac863bSchristos }
690*04ac863bSchristos 
691*04ac863bSchristos 
692*04ac863bSchristos /*
693*04ac863bSchristos Local Variables:
694*04ac863bSchristos c-indent-level: 8
695*04ac863bSchristos c-continued-statement-offset: 8
696*04ac863bSchristos c-brace-offset: -8
697*04ac863bSchristos c-argdecl-indent: 8
698*04ac863bSchristos c-label-offset: -8
699*04ac863bSchristos c-tab-always-indent: nil
700*04ac863bSchristos End:
701*04ac863bSchristos */
702