~ubuntu-branches/ubuntu/dapper/groff/dapper

« back to all changes in this revision

Viewing changes to src/xditview/draw.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2002-03-17 04:11:50 UTC
  • Revision ID: james.westby@ubuntu.com-20020317041150-wkgfawjc3gxlk0o5
Tags: upstream-1.17.2
ImportĀ upstreamĀ versionĀ 1.17.2

Show diffs side-by-side

added added

removed removed

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