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