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