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