1151497Sru/*
2151497Sru * draw.c
3151497Sru *
4151497Sru * accept dvi function calls and translate to X
5151497Sru */
6151497Sru
7151497Sru#include <X11/Xos.h>
8151497Sru#include <X11/IntrinsicP.h>
9151497Sru#include <X11/StringDefs.h>
10151497Sru#include <stdio.h>
11151497Sru#include <ctype.h>
12151497Sru#include <math.h>
13151497Sru
14151497Sru/* math.h on a Sequent doesn't define M_PI, apparently */
15151497Sru#ifndef M_PI
16151497Sru#define M_PI	3.14159265358979323846
17151497Sru#endif
18151497Sru
19151497Sru#include "DviP.h"
20151497Sru
21151497Sru#define DeviceToX(dw, n) ((int)((n) * (dw)->dvi.scale_factor + .5))
22151497Sru#define XPos(dw) (DeviceToX((dw), (dw)->dvi.state->x - \
23151497Sru                  (dw)->dvi.text_device_width) + (dw)->dvi.text_x_width)
24151497Sru#define YPos(dw) (DeviceToX((dw), (dw)->dvi.state->y))
25151497Sru
26151497Srustatic int FakeCharacter(DviWidget, char *, int);
27151497Sru
28151497Sru/* font.c */
29151497Sruextern int MaxFontPosition(DviWidget);
30151497Sru
31151497Sruvoid
32151497SruHorizontalMove(DviWidget dw, int delta)
33151497Sru{
34151497Sru	dw->dvi.state->x += delta;
35151497Sru}
36151497Sru
37151497Sruvoid
38151497SruHorizontalGoto(DviWidget dw, int NewPosition)
39151497Sru{
40151497Sru	dw->dvi.state->x = NewPosition;
41151497Sru}
42151497Sru
43151497Sruvoid
44151497SruVerticalMove(DviWidget dw, int delta)
45151497Sru{
46151497Sru	dw->dvi.state->y += delta;
47151497Sru}
48151497Sru
49151497Sruvoid
50151497SruVerticalGoto(DviWidget dw, int NewPosition)
51151497Sru{
52151497Sru	dw->dvi.state->y = NewPosition;
53151497Sru}
54151497Sru
55151497Sruvoid
56151497SruAdjustCacheDeltas (DviWidget dw)
57151497Sru{
58151497Sru	int extra;
59151497Sru	int nadj;
60151497Sru	int i;
61151497Sru
62151497Sru	nadj = 0;
63151497Sru	extra = DeviceToX(dw, dw->dvi.text_device_width)
64151497Sru		- dw->dvi.text_x_width;
65151497Sru	if (extra == 0)
66151497Sru		return;
67151497Sru	for (i = 0; i <= dw->dvi.cache.index; i++)
68151497Sru		if (dw->dvi.cache.adjustable[i])
69151497Sru			++nadj;
70151497Sru	dw->dvi.text_x_width += extra;
71151497Sru	if (nadj <= 1)
72151497Sru		return;
73151497Sru	for (i = 0; i <= dw->dvi.cache.index; i++)
74151497Sru		if (dw->dvi.cache.adjustable[i]) {
75151497Sru			int x;
76151497Sru			int *deltap;
77151497Sru
78151497Sru			x = extra/nadj;
79151497Sru			deltap = &dw->dvi.cache.cache[i].delta;
80151497Sru#define MIN_DELTA 2
81151497Sru			if (*deltap > 0 && x + *deltap < MIN_DELTA) {
82151497Sru				x = MIN_DELTA - *deltap;
83151497Sru				if (x <= 0)
84151497Sru					*deltap = MIN_DELTA;
85151497Sru				else
86151497Sru					x = 0;
87151497Sru			}
88151497Sru			else
89151497Sru				*deltap += x;
90151497Sru			extra -= x;
91151497Sru			--nadj;
92151497Sru			dw->dvi.cache.adjustable[i] = 0;
93151497Sru		}
94151497Sru}
95151497Sru
96151497Sruvoid
97151497SruFlushCharCache (DviWidget dw)
98151497Sru{
99151497Sru	if (dw->dvi.cache.char_index != 0) {
100151497Sru		AdjustCacheDeltas (dw);
101151497Sru		XDrawText (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
102151497Sru			   dw->dvi.cache.start_x, dw->dvi.cache.start_y,
103151497Sru			   dw->dvi.cache.cache, dw->dvi.cache.index + 1);
104151497Sru	}
105151497Sru	dw->dvi.cache.index = 0;
106151497Sru	dw->dvi.cache.max = DVI_TEXT_CACHE_SIZE;
107151497Sru#if 0
108151497Sru	if (dw->dvi.noPolyText)
109151497Sru	    dw->dvi.cache.max = 1;
110151497Sru#endif
111151497Sru	dw->dvi.cache.char_index = 0;
112151497Sru	dw->dvi.cache.cache[0].nchars = 0;
113151497Sru	dw->dvi.cache.start_x = dw->dvi.cache.x	= XPos (dw);
114151497Sru	dw->dvi.cache.start_y = dw->dvi.cache.y = YPos (dw);
115151497Sru}
116151497Sru
117151497Sruvoid
118151497SruNewline (DviWidget dw)
119151497Sru{
120151497Sru	FlushCharCache (dw);
121151497Sru	dw->dvi.text_x_width = dw->dvi.text_device_width = 0;
122151497Sru	dw->dvi.word_flag = 0;
123151497Sru}
124151497Sru
125151497Sruvoid
126151497SruWord (DviWidget dw)
127151497Sru{
128151497Sru	dw->dvi.word_flag = 1;
129151497Sru}
130151497Sru
131151497Sru#define charWidth(fi,c) (\
132151497Sru    (fi)->per_char ?\
133151497Sru	(fi)->per_char[(c) - (fi)->min_char_or_byte2].width\
134151497Sru    :\
135151497Sru	(fi)->max_bounds.width\
136151497Sru)
137151497Sru
138151497Sru
139151497Srustatic
140151497Sruint charExists (XFontStruct *fi, int c)
141151497Sru{
142151497Sru	XCharStruct *p;
143151497Sru
144151497Sru	/* `c' is always >= 0 */
145151497Sru	if (fi->per_char == NULL
146151497Sru	    || (unsigned int)c < fi->min_char_or_byte2
147151497Sru	    || (unsigned int)c > fi->max_char_or_byte2)
148151497Sru		return 0;
149151497Sru	p = fi->per_char + (c - fi->min_char_or_byte2);
150151497Sru	return (p->lbearing != 0 || p->rbearing != 0 || p->width != 0
151151497Sru		|| p->ascent != 0 || p->descent != 0 || p->attributes != 0);
152151497Sru}
153151497Sru
154151497Sru/* `wid' is in device units */
155151497Srustatic void
156151497SruDoCharacter (DviWidget dw, int c, int wid)
157151497Sru{
158151497Sru	register XFontStruct	*font;
159151497Sru	register XTextItem	*text;
160151497Sru	int	x, y;
161151497Sru
162151497Sru	x = XPos(dw);
163151497Sru	y = YPos(dw);
164151497Sru
165151497Sru	/*
166151497Sru	 * quick and dirty extents calculation:
167151497Sru	 */
168151497Sru	if (!(y + 24 >= dw->dvi.extents.y1
169151497Sru	      && y - 24 <= dw->dvi.extents.y2
170151497Sru#if 0
171151497Sru	      && x + 24 >= dw->dvi.extents.x1
172151497Sru	      && x - 24 <= dw->dvi.extents.x2
173151497Sru#endif
174151497Sru	    ))
175151497Sru		return;
176151497Sru
177151497Sru	if (y != dw->dvi.cache.y
178151497Sru	    || dw->dvi.cache.char_index >= DVI_CHAR_CACHE_SIZE) {
179151497Sru		FlushCharCache (dw);
180151497Sru		x = dw->dvi.cache.x;
181151497Sru		dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0;
182151497Sru	}
183151497Sru	/*
184151497Sru	 * load a new font, if the current block is not empty,
185151497Sru	 * step to the next.
186151497Sru	 */
187151497Sru	if (dw->dvi.cache.font_size != dw->dvi.state->font_size ||
188151497Sru	    dw->dvi.cache.font_number != dw->dvi.state->font_number)
189151497Sru	{
190151497Sru		FlushCharCache (dw);
191151497Sru		x = dw->dvi.cache.x;
192151497Sru		dw->dvi.cache.font_size = dw->dvi.state->font_size;
193151497Sru		dw->dvi.cache.font_number = dw->dvi.state->font_number;
194151497Sru		dw->dvi.cache.font = QueryFont (dw,
195151497Sru						dw->dvi.cache.font_number,
196151497Sru						dw->dvi.cache.font_size);
197151497Sru		if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
198151497Sru			++dw->dvi.cache.index;
199151497Sru			if (dw->dvi.cache.index >= dw->dvi.cache.max)
200151497Sru				FlushCharCache (dw);
201151497Sru			dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
202151497Sru			dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0;
203151497Sru		}
204151497Sru	}
205151497Sru	if (x != dw->dvi.cache.x || dw->dvi.word_flag) {
206151497Sru		if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
207151497Sru			++dw->dvi.cache.index;
208151497Sru			if (dw->dvi.cache.index >= dw->dvi.cache.max)
209151497Sru				FlushCharCache (dw);
210151497Sru			dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
211151497Sru			dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0;
212151497Sru		}
213151497Sru		dw->dvi.cache.adjustable[dw->dvi.cache.index]
214151497Sru			= dw->dvi.word_flag;
215151497Sru		dw->dvi.word_flag = 0;
216151497Sru	}
217151497Sru	font = dw->dvi.cache.font;
218151497Sru	text = &dw->dvi.cache.cache[dw->dvi.cache.index];
219151497Sru	if (text->nchars == 0) {
220151497Sru		text->chars = &dw->dvi.cache.char_cache[dw->dvi.cache.char_index];
221151497Sru		text->delta = x - dw->dvi.cache.x;
222151497Sru		if (font != dw->dvi.font) {
223151497Sru			text->font = font->fid;
224151497Sru			dw->dvi.font = font;
225151497Sru		} else
226151497Sru			text->font = None;
227151497Sru		dw->dvi.cache.x += text->delta;
228151497Sru	}
229151497Sru	if (charExists(font, c)) {
230151497Sru		int w;
231151497Sru		dw->dvi.cache.char_cache[dw->dvi.cache.char_index++] = (char) c;
232151497Sru		++text->nchars;
233151497Sru		w = charWidth(font, c);
234151497Sru		dw->dvi.cache.x += w;
235151497Sru		if (wid != 0) {
236151497Sru			dw->dvi.text_x_width += w;
237151497Sru			dw->dvi.text_device_width += wid;
238151497Sru		}
239151497Sru	}
240151497Sru}
241151497Sru
242151497Srustatic
243151497Sruint FindCharWidth (DviWidget dw, char *buf, int *widp)
244151497Sru{
245151497Sru	int maxpos;
246151497Sru	int i;
247151497Sru
248151497Sru	if (dw->dvi.device_font == 0
249151497Sru	    || dw->dvi.state->font_number != dw->dvi.device_font_number) {
250151497Sru		dw->dvi.device_font_number = dw->dvi.state->font_number;
251151497Sru		dw->dvi.device_font
252151497Sru			= QueryDeviceFont (dw, dw->dvi.device_font_number);
253151497Sru	}
254151497Sru	if (dw->dvi.device_font
255151497Sru	    && device_char_width (dw->dvi.device_font,
256151497Sru				  dw->dvi.state->font_size, buf, widp))
257151497Sru		return 1;
258151497Sru
259151497Sru	maxpos = MaxFontPosition (dw);
260151497Sru	for (i = 1; i <= maxpos; i++) {
261151497Sru		DeviceFont *f = QueryDeviceFont (dw, i);
262151497Sru		if (f && device_font_special (f)
263151497Sru		    && device_char_width (f, dw->dvi.state->font_size,
264151497Sru					  buf, widp)) {
265151497Sru			dw->dvi.state->font_number = i;
266151497Sru			return 1;
267151497Sru		}
268151497Sru	}
269151497Sru	return 0;
270151497Sru}
271151497Sru
272151497Sru/* Return the width of the character in device units. */
273151497Sru
274151497Sruint PutCharacter (DviWidget dw, char *buf)
275151497Sru{
276151497Sru	int		prevFont;
277151497Sru	int		c = -1;
278151497Sru	int		wid = 0;
279151497Sru	DviCharNameMap	*map;
280151497Sru
281151497Sru	if (!dw->dvi.display_enable)
282151497Sru		return 0;	/* The width doesn't matter in this case. */
283151497Sru	prevFont = dw->dvi.state->font_number;
284151497Sru	if (!FindCharWidth (dw, buf, &wid))
285151497Sru		return 0;
286151497Sru	map = QueryFontMap (dw, dw->dvi.state->font_number);
287151497Sru	if (map)
288151497Sru		c = DviCharIndex (map, buf);
289151497Sru	if (c >= 0)
290151497Sru		DoCharacter (dw, c, wid);
291151497Sru	else
292151497Sru		(void) FakeCharacter (dw, buf, wid);
293151497Sru	dw->dvi.state->font_number = prevFont;
294151497Sru	return wid;
295151497Sru}
296151497Sru
297151497Sru/* Return 1 if we can fake it; 0 otherwise. */
298151497Sru
299151497Srustatic
300151497Sruint FakeCharacter (DviWidget dw, char *buf, int wid)
301151497Sru{
302151497Sru	int oldx, oldw;
303151497Sru	char ch[2];
304151497Sru	const char *chars = 0;
305151497Sru
306151497Sru	if (buf[0] == '\0' || buf[1] == '\0' || buf[2] != '\0')
307151497Sru		return 0;
308151497Sru#define pack2(c1, c2) (((c1) << 8) | (c2))
309151497Sru
310151497Sru	switch (pack2(buf[0], buf[1])) {
311151497Sru	case pack2('f', 'i'):
312151497Sru		chars = "fi";
313151497Sru		break;
314151497Sru	case pack2('f', 'l'):
315151497Sru		chars = "fl";
316151497Sru		break;
317151497Sru	case pack2('f', 'f'):
318151497Sru		chars = "ff";
319151497Sru		break;
320151497Sru	case pack2('F', 'i'):
321151497Sru		chars = "ffi";
322151497Sru		break;
323151497Sru	case pack2('F', 'l'):
324151497Sru		chars = "ffl";
325151497Sru		break;
326151497Sru	}
327151497Sru	if (!chars)
328151497Sru		return 0;
329151497Sru	oldx = dw->dvi.state->x;
330151497Sru	oldw = dw->dvi.text_device_width;
331151497Sru	ch[1] = '\0';
332151497Sru	for (; *chars; chars++) {
333151497Sru		ch[0] = *chars;
334151497Sru		dw->dvi.state->x += PutCharacter (dw, ch);
335151497Sru	}
336151497Sru	dw->dvi.state->x = oldx;
337151497Sru	dw->dvi.text_device_width = oldw + wid;
338151497Sru	return 1;
339151497Sru}
340151497Sru
341151497Sruvoid
342151497SruPutNumberedCharacter (DviWidget dw, int c)
343151497Sru{
344151497Sru	char *name;
345151497Sru	int wid;
346151497Sru	DviCharNameMap	*map;
347151497Sru
348151497Sru	if (!dw->dvi.display_enable)
349151497Sru		return;
350151497Sru
351151497Sru	if (dw->dvi.device_font == 0
352151497Sru	    || dw->dvi.state->font_number != dw->dvi.device_font_number) {
353151497Sru		dw->dvi.device_font_number = dw->dvi.state->font_number;
354151497Sru		dw->dvi.device_font
355151497Sru			= QueryDeviceFont (dw, dw->dvi.device_font_number);
356151497Sru	}
357151497Sru
358151497Sru	if (dw->dvi.device_font == 0
359151497Sru	    || !device_code_width (dw->dvi.device_font,
360151497Sru				   dw->dvi.state->font_size, c, &wid))
361151497Sru		return;
362151497Sru	if (dw->dvi.native) {
363151497Sru		DoCharacter (dw, c, wid);
364151497Sru		return;
365151497Sru	}
366151497Sru	map = QueryFontMap (dw, dw->dvi.state->font_number);
367151497Sru	if (!map)
368151497Sru		return;
369151497Sru	for (name = device_name_for_code (dw->dvi.device_font, c);
370151497Sru	     name;
371151497Sru	     name = device_name_for_code ((DeviceFont *)0, c)) {
372151497Sru		int code = DviCharIndex (map, name);
373151497Sru		if (code >= 0) {
374151497Sru			DoCharacter (dw, code, wid);
375151497Sru			break;
376151497Sru		}
377151497Sru		if (FakeCharacter (dw, name, wid))
378151497Sru			break;
379151497Sru	}
380151497Sru}
381151497Sru
382151497Sruvoid
383151497SruClearPage (DviWidget dw)
384151497Sru{
385151497Sru	XClearWindow (XtDisplay (dw), XtWindow (dw));
386151497Sru}
387151497Sru
388151497Srustatic void
389151497SrusetGC (DviWidget dw)
390151497Sru{
391151497Sru	int desired_line_width;
392151497Sru
393151497Sru	if (dw->dvi.line_thickness < 0)
394151497Sru		desired_line_width = (int)(((double)dw->dvi.device_resolution
395151497Sru					    * dw->dvi.state->font_size)
396151497Sru					   / (10.0*72.0*dw->dvi.sizescale));
397151497Sru	else
398151497Sru		desired_line_width = dw->dvi.line_thickness;
399151497Sru
400151497Sru	if (desired_line_width != dw->dvi.line_width) {
401151497Sru		XGCValues values;
402151497Sru		values.line_width = DeviceToX(dw, desired_line_width);
403151497Sru		if (values.line_width == 0)
404151497Sru			values.line_width = 1;
405151497Sru		XChangeGC(XtDisplay (dw), dw->dvi.normal_GC,
406151497Sru			  GCLineWidth, &values);
407151497Sru		dw->dvi.line_width = desired_line_width;
408151497Sru	}
409151497Sru}
410151497Sru
411151497Srustatic void
412151497SrusetFillGC (DviWidget dw)
413151497Sru{
414151497Sru	int fill_type;
415151497Sru	unsigned long mask = GCFillStyle | GCForeground;
416151497Sru
417151497Sru	fill_type = (dw->dvi.fill * 10) / (DVI_FILL_MAX + 1);
418151497Sru	if (dw->dvi.fill_type != fill_type) {
419151497Sru		XGCValues values;
420151497Sru		if (fill_type <= 0) {
421151497Sru			values.foreground = dw->dvi.background;
422151497Sru			values.fill_style = FillSolid;
423151497Sru		} else if (fill_type >= 9) {
424151497Sru			values.foreground = dw->dvi.foreground;
425151497Sru			values.fill_style = FillSolid;
426151497Sru		} else {
427151497Sru			values.foreground = dw->dvi.foreground;
428151497Sru			values.fill_style = FillOpaqueStippled;
429151497Sru			values.stipple = dw->dvi.gray[fill_type - 1];
430151497Sru			mask |= GCStipple;
431151497Sru		}
432151497Sru		XChangeGC(XtDisplay (dw), dw->dvi.fill_GC, mask, &values);
433151497Sru		dw->dvi.fill_type = fill_type;
434151497Sru	}
435151497Sru}
436151497Sru
437151497Sruvoid
438151497SruDrawLine (DviWidget dw, int x, int y)
439151497Sru{
440151497Sru	int xp, yp;
441151497Sru
442151497Sru	AdjustCacheDeltas (dw);
443151497Sru	setGC (dw);
444151497Sru	xp = XPos (dw);
445151497Sru	yp = YPos (dw);
446151497Sru	XDrawLine (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
447151497Sru		   xp, yp,
448151497Sru		   xp + DeviceToX (dw, x), yp + DeviceToX (dw, y));
449151497Sru}
450151497Sru
451151497Sruvoid
452151497SruDrawCircle (DviWidget dw, int diam)
453151497Sru{
454151497Sru	int d;
455151497Sru
456151497Sru	AdjustCacheDeltas (dw);
457151497Sru	setGC (dw);
458151497Sru	d = DeviceToX (dw, diam);
459151497Sru	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
460151497Sru		  XPos (dw), YPos (dw) - d/2,
461151497Sru		  d, d, 0, 64*360);
462151497Sru}
463151497Sru
464151497Sruvoid
465151497SruDrawFilledCircle (DviWidget dw, int diam)
466151497Sru{
467151497Sru	int d;
468151497Sru
469151497Sru	AdjustCacheDeltas (dw);
470151497Sru	setFillGC (dw);
471151497Sru	d = DeviceToX (dw, diam);
472151497Sru	XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
473151497Sru		  XPos (dw), YPos (dw) - d/2,
474151497Sru		  d, d, 0, 64*360);
475151497Sru	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
476151497Sru		  XPos (dw), YPos (dw) - d/2,
477151497Sru		  d, d, 0, 64*360);
478151497Sru}
479151497Sru
480151497Sruvoid
481151497SruDrawEllipse (DviWidget dw, int a, int b)
482151497Sru{
483151497Sru	AdjustCacheDeltas (dw);
484151497Sru	setGC (dw);
485151497Sru	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
486151497Sru		  XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
487151497Sru		  DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
488151497Sru}
489151497Sru
490151497Sruvoid
491151497SruDrawFilledEllipse (DviWidget dw, int a, int b)
492151497Sru{
493151497Sru	AdjustCacheDeltas (dw);
494151497Sru	setFillGC (dw);
495151497Sru	XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
496151497Sru		  XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
497151497Sru		  DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
498151497Sru	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
499151497Sru		  XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
500151497Sru		  DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
501151497Sru}
502151497Sru
503151497Sruvoid
504151497SruDrawArc (DviWidget dw, int x_0, int y_0, int x_1, int y_1)
505151497Sru{
506151497Sru	int angle1, angle2;
507151497Sru	int rad = (int)((sqrt ((double)x_0*x_0 + (double)y_0*y_0)
508151497Sru			 + sqrt ((double)x_1*x_1 + (double)y_1*y_1)
509151497Sru			 + 1.0)/2.0);
510151497Sru	if ((x_0 == 0 && y_0 == 0) || (x_1 == 0 && y_1 == 0))
511151497Sru		return;
512151497Sru	angle1 = (int)(atan2 ((double)y_0, (double)-x_0)*180.0*64.0/M_PI);
513151497Sru	angle2 = (int)(atan2 ((double)-y_1, (double)x_1)*180.0*64.0/M_PI);
514151497Sru
515151497Sru	angle2 -= angle1;
516151497Sru	if (angle2 < 0)
517151497Sru		angle2 += 64*360;
518151497Sru
519151497Sru	AdjustCacheDeltas (dw);
520151497Sru	setGC (dw);
521151497Sru
522151497Sru	rad = DeviceToX (dw, rad);
523151497Sru	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
524151497Sru		  XPos (dw) + DeviceToX (dw, x_0) - rad,
525151497Sru		  YPos (dw) + DeviceToX (dw, y_0) - rad,
526151497Sru		  rad*2, rad*2, angle1, angle2);
527151497Sru}
528151497Sru
529151497Sruvoid
530151497SruDrawPolygon (DviWidget dw, int *v, int n)
531151497Sru{
532151497Sru	XPoint *p;
533151497Sru	int i;
534151497Sru	int dx, dy;
535151497Sru
536151497Sru	n /= 2;
537151497Sru
538151497Sru	AdjustCacheDeltas (dw);
539151497Sru	setGC (dw);
540151497Sru	p = (XPoint *)XtMalloc((n + 2)*sizeof(XPoint));
541151497Sru	p[0].x = XPos (dw);
542151497Sru	p[0].y = YPos (dw);
543151497Sru	dx = 0;
544151497Sru	dy = 0;
545151497Sru	for (i = 0; i < n; i++) {
546151497Sru		dx += v[2*i];
547151497Sru		p[i + 1].x = DeviceToX (dw, dx) + p[0].x;
548151497Sru		dy += v[2*i + 1];
549151497Sru		p[i + 1].y = DeviceToX (dw, dy) + p[0].y;
550151497Sru	}
551151497Sru	p[n+1].x = p[0].x;
552151497Sru	p[n+1].y = p[0].y;
553151497Sru	XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
554151497Sru		   p, n + 2, CoordModeOrigin);
555151497Sru	XtFree((char *)p);
556151497Sru}
557151497Sru
558151497Sruvoid
559151497SruDrawFilledPolygon (DviWidget dw, int *v, int n)
560151497Sru{
561151497Sru	XPoint *p;
562151497Sru	int i;
563151497Sru	int dx, dy;
564151497Sru
565151497Sru	n /= 2;
566151497Sru	if (n < 2)
567151497Sru		return;
568151497Sru
569151497Sru	AdjustCacheDeltas (dw);
570151497Sru	setFillGC (dw);
571151497Sru	p = (XPoint *)XtMalloc((n + 2)*sizeof(XPoint));
572151497Sru	p[0].x = p[n+1].x = XPos (dw);
573151497Sru	p[0].y = p[n+1].y = YPos (dw);
574151497Sru	dx = 0;
575151497Sru	dy = 0;
576151497Sru	for (i = 0; i < n; i++) {
577151497Sru		dx += v[2*i];
578151497Sru		p[i + 1].x = DeviceToX (dw, dx) + p[0].x;
579151497Sru		dy += v[2*i + 1];
580151497Sru		p[i + 1].y = DeviceToX (dw, dy) + p[0].y;
581151497Sru	}
582151497Sru	XFillPolygon (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
583151497Sru		      p, n + 1, Complex, CoordModeOrigin);
584151497Sru	XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
585151497Sru		      p, n + 2, CoordModeOrigin);
586151497Sru	XtFree((char *)p);
587151497Sru}
588151497Sru
589151497Sru#define POINTS_MAX 10000
590151497Sru
591151497Srustatic void
592151497SruappendPoint(XPoint *points, int *pointi, int x, int y)
593151497Sru{
594151497Sru	if (*pointi < POINTS_MAX) {
595151497Sru		points[*pointi].x = x;
596151497Sru		points[*pointi].y = y;
597151497Sru		*pointi += 1;
598151497Sru	}
599151497Sru}
600151497Sru
601151497Sru#define FLATNESS 1
602151497Sru
603151497Srustatic void
604151497SruflattenCurve(XPoint *points, int *pointi,
605151497Sru	     int x_2, int y_2, int x_3, int y_3, int x_4, int y_4)
606151497Sru{
607151497Sru	int x_1, y_1, dx, dy, n1, n2, n;
608151497Sru
609151497Sru	x_1 = points[*pointi - 1].x;
610151497Sru	y_1 = points[*pointi - 1].y;
611151497Sru
612151497Sru	dx = x_4 - x_1;
613151497Sru	dy = y_4 - y_1;
614151497Sru
615151497Sru	n1 = dy*(x_2 - x_1) - dx*(y_2 - y_1);
616151497Sru	n2 = dy*(x_3 - x_1) - dx*(y_3 - y_1);
617151497Sru	if (n1 < 0)
618151497Sru		n1 = -n1;
619151497Sru	if (n2 < 0)
620151497Sru		n2 = -n2;
621151497Sru	n = n1 > n2 ? n1 : n2;
622151497Sru
623151497Sru	if (n*n / (dy*dy + dx*dx) <= FLATNESS*FLATNESS)
624151497Sru		appendPoint (points, pointi, x_4, y_4);
625151497Sru	else {
626151497Sru		flattenCurve (points, pointi,
627151497Sru			      (x_1 + x_2)/2,
628151497Sru			      (y_1 + y_2)/2,
629151497Sru			      (x_1 + x_2*2 + x_3)/4,
630151497Sru			      (y_1 + y_2*2 + y_3)/4,
631151497Sru			      (x_1 + 3*x_2 + 3*x_3 + x_4)/8,
632151497Sru			      (y_1 + 3*y_2 + 3*y_3 + y_4)/8);
633151497Sru		flattenCurve (points, pointi,
634151497Sru			      (x_2 + x_3*2 + x_4)/4,
635151497Sru			      (y_2 + y_3*2 + y_4)/4,
636151497Sru			      (x_3 + x_4)/2,
637151497Sru			      (y_3 + y_4)/2,
638151497Sru			      x_4,
639151497Sru			      y_4);
640151497Sru	}
641151497Sru}
642151497Sru
643151497Sruvoid
644151497SruDrawSpline (DviWidget dw, int *v, int n)
645151497Sru{
646151497Sru	int sx, sy, tx, ty;
647151497Sru	int ox, oy, dx, dy;
648151497Sru	int i;
649151497Sru	int pointi;
650151497Sru	XPoint points[POINTS_MAX];
651151497Sru
652151497Sru	if (n == 0 || (n & 1) != 0)
653151497Sru		return;
654151497Sru	AdjustCacheDeltas (dw);
655151497Sru	setGC (dw);
656151497Sru	ox = XPos (dw);
657151497Sru	oy = YPos (dw);
658151497Sru	dx = v[0];
659151497Sru	dy = v[1];
660151497Sru	sx = ox;
661151497Sru	sy = oy;
662151497Sru	tx = sx + DeviceToX (dw, dx);
663151497Sru	ty = sy + DeviceToX (dw, dy);
664151497Sru
665151497Sru	pointi = 0;
666151497Sru
667151497Sru	appendPoint (points, &pointi, sx, sy);
668151497Sru	appendPoint (points, &pointi, (sx + tx)/2, (sy + ty)/2);
669151497Sru
670151497Sru	for (i = 2; i < n; i += 2) {
671151497Sru		int ux = ox + DeviceToX (dw, dx += v[i]);
672151497Sru		int uy = oy + DeviceToX (dw, dy += v[i+1]);
673151497Sru		flattenCurve (points, &pointi,
674151497Sru			       (sx + tx*5)/6, (sy + ty*5)/6,
675151497Sru			       (tx*5 + ux)/6, (ty*5 + uy)/6,
676151497Sru			       (tx + ux)/2, (ty + uy)/2);
677151497Sru		sx = tx;
678151497Sru		sy = ty;
679151497Sru		tx = ux;
680151497Sru		ty = uy;
681151497Sru	}
682151497Sru
683151497Sru	appendPoint (points, &pointi, tx, ty);
684151497Sru
685151497Sru	XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
686151497Sru		   points, pointi, CoordModeOrigin);
687151497Sru}
688151497Sru
689151497Sru
690151497Sru/*
691151497SruLocal Variables:
692151497Sruc-indent-level: 8
693151497Sruc-continued-statement-offset: 8
694151497Sruc-brace-offset: -8
695151497Sruc-argdecl-indent: 8
696151497Sruc-label-offset: -8
697151497Sruc-tab-always-indent: nil
698151497SruEnd:
699151497Sru*/
700