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